@digdir/designsystemet-react 1.0.0-next.15 → 1.0.0-next.16

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 (309) hide show
  1. package/dist/cjs/components/Accordion/index.js +2 -2
  2. package/dist/cjs/components/Breadcrumbs/BreadcrumbsItem.js +11 -0
  3. package/dist/cjs/components/Breadcrumbs/BreadcrumbsLink.js +12 -0
  4. package/dist/cjs/components/Breadcrumbs/BreadcrumbsList.js +23 -0
  5. package/dist/cjs/components/Breadcrumbs/BreadcrumbsNav.js +11 -0
  6. package/dist/cjs/components/Breadcrumbs/BreadcrumbsRoot.js +11 -0
  7. package/dist/cjs/components/Breadcrumbs/index.js +43 -0
  8. package/dist/cjs/components/Divider/Divider.js +3 -4
  9. package/dist/cjs/components/DropdownMenu/DropdownMenuContent.js +2 -2
  10. package/dist/cjs/components/Modal/ModalDialog.js +1 -2
  11. package/dist/cjs/components/Modal/ModalHeader.js +2 -2
  12. package/dist/cjs/components/Modal/index.js +1 -0
  13. package/dist/cjs/components/Popover/PopoverContent.js +3 -4
  14. package/dist/cjs/components/Tabs/TabList.js +1 -1
  15. package/dist/cjs/components/ToggleGroup/ToggleGroupRoot.js +1 -1
  16. package/dist/cjs/components/Tooltip/Tooltip.js +3 -4
  17. package/dist/cjs/components/form/Checkbox/{Group/Group.js → CheckboxGroup.js} +3 -2
  18. package/dist/cjs/components/form/Checkbox/index.js +3 -3
  19. package/dist/cjs/components/form/Checkbox/useCheckbox.js +2 -2
  20. package/dist/cjs/components/form/Combobox/Combobox.js +2 -2
  21. package/dist/cjs/components/form/Combobox/Option/Description.js +1 -2
  22. package/dist/cjs/components/form/Combobox/internal/ComboboxChips.js +1 -2
  23. package/dist/cjs/components/form/Combobox/internal/ComboboxClearButton.js +1 -2
  24. package/dist/cjs/components/form/Combobox/internal/ComboboxError.js +1 -2
  25. package/dist/cjs/components/form/Combobox/internal/ComboboxInput.js +5 -6
  26. package/dist/cjs/components/form/Combobox/internal/ComboboxLabel.js +1 -2
  27. package/dist/cjs/components/form/Combobox/internal/ComboboxNative.js +1 -2
  28. package/dist/cjs/components/form/Combobox/useCombobox.js +5 -0
  29. package/dist/cjs/components/form/Combobox/useFloatingCombobox.js +4 -4
  30. package/dist/cjs/components/form/NativeSelect/NativeSelect.js +2 -2
  31. package/dist/cjs/components/form/NativeSelect/useNativeSelect.js +19 -1
  32. package/dist/cjs/components/form/Radio/{Group/Group.js → RadioGroup.js} +3 -3
  33. package/dist/cjs/components/form/Radio/index.js +3 -3
  34. package/dist/cjs/components/form/Radio/useRadio.js +2 -2
  35. package/dist/cjs/components/form/Switch/useSwitch.js +2 -2
  36. package/dist/cjs/index.js +50 -36
  37. package/dist/cjs/node_modules/@floating-ui/core/dist/floating-ui.core.js +23 -9
  38. package/dist/cjs/node_modules/@floating-ui/dom/dist/floating-ui.dom.js +39 -24
  39. package/dist/cjs/node_modules/@floating-ui/react/dist/floating-ui.react.js +848 -729
  40. package/dist/cjs/node_modules/@floating-ui/react/dist/floating-ui.react.utils.js +1 -1
  41. package/dist/cjs/node_modules/@floating-ui/react/node_modules/@floating-ui/utils/dist/floating-ui.utils.dom.js +68 -0
  42. package/dist/cjs/node_modules/@floating-ui/react/node_modules/@floating-ui/utils/dist/floating-ui.utils.js +11 -0
  43. package/dist/cjs/node_modules/@floating-ui/react-dom/dist/floating-ui.react-dom.js +97 -45
  44. package/dist/cjs/node_modules/@floating-ui/utils/dist/floating-ui.utils.dom.js +17 -6
  45. package/dist/cjs/node_modules/@floating-ui/utils/dist/floating-ui.utils.js +14 -5
  46. package/dist/cjs/node_modules/@radix-ui/react-compose-refs/dist/index.js +10 -14
  47. package/dist/cjs/node_modules/@radix-ui/react-slot/dist/index.js +88 -69
  48. package/dist/cjs/node_modules/@tanstack/virtual-core/dist/esm/index.js +134 -62
  49. package/dist/cjs/node_modules/@tanstack/virtual-core/dist/esm/utils.js +3 -5
  50. package/dist/cjs/utilities/AnimateHeight/AnimateHeight.js +4 -1
  51. package/dist/cjs/utilities/RovingFocus/RovingFocusItem.js +34 -6
  52. package/dist/cjs/utilities/RovingFocus/RovingFocusRoot.js +3 -1
  53. package/dist/cjs/utilities/RovingFocus/useRovingFocus.js +2 -1
  54. package/dist/esm/components/Accordion/index.js +2 -2
  55. package/dist/esm/components/Box/Box.js +2 -2
  56. package/dist/esm/components/Breadcrumbs/BreadcrumbsItem.js +9 -0
  57. package/dist/esm/components/Breadcrumbs/BreadcrumbsLink.js +10 -0
  58. package/dist/esm/components/Breadcrumbs/BreadcrumbsList.js +21 -0
  59. package/dist/esm/components/Breadcrumbs/BreadcrumbsNav.js +9 -0
  60. package/dist/esm/components/Breadcrumbs/BreadcrumbsRoot.js +9 -0
  61. package/dist/esm/components/Breadcrumbs/index.js +36 -0
  62. package/dist/esm/components/Button/Button.js +2 -2
  63. package/dist/esm/components/Card/Card.js +2 -2
  64. package/dist/esm/components/Card/CardContent.js +2 -2
  65. package/dist/esm/components/Card/CardFooter.js +2 -2
  66. package/dist/esm/components/Card/CardHeader.js +2 -2
  67. package/dist/esm/components/Card/CardMedia.js +2 -2
  68. package/dist/esm/components/Divider/Divider.js +3 -4
  69. package/dist/esm/components/DropdownMenu/DropdownMenuContent.js +2 -2
  70. package/dist/esm/components/DropdownMenu/DropdownMenuTrigger.js +2 -2
  71. package/dist/esm/components/ErrorSummary/ErrorSummaryRoot.js +2 -2
  72. package/dist/esm/components/Link/Link.js +2 -2
  73. package/dist/esm/components/List/ListItem.js +2 -2
  74. package/dist/esm/components/List/ListRoot.js +2 -2
  75. package/dist/esm/components/List/Lists.js +3 -3
  76. package/dist/esm/components/Modal/ModaContent.js +2 -2
  77. package/dist/esm/components/Modal/ModalDialog.js +5 -6
  78. package/dist/esm/components/Modal/ModalFooter.js +2 -2
  79. package/dist/esm/components/Modal/ModalHeader.js +4 -4
  80. package/dist/esm/components/Modal/ModalTrigger.js +2 -2
  81. package/dist/esm/components/Modal/index.js +1 -1
  82. package/dist/esm/components/Pagination/PaginationContent.js +2 -2
  83. package/dist/esm/components/Pagination/PaginationItem.js +2 -2
  84. package/dist/esm/components/Pagination/PaginationRoot.js +2 -2
  85. package/dist/esm/components/Popover/PopoverContent.js +2 -3
  86. package/dist/esm/components/Popover/PopoverTrigger.js +2 -2
  87. package/dist/esm/components/Tabs/TabList.js +1 -1
  88. package/dist/esm/components/ToggleGroup/ToggleGroupRoot.js +1 -1
  89. package/dist/esm/components/Tooltip/Tooltip.js +2 -3
  90. package/dist/esm/components/Typography/ErrorMessage/ErrorMessage.js +2 -2
  91. package/dist/esm/components/Typography/Heading/Heading.js +2 -2
  92. package/dist/esm/components/Typography/Ingress/Ingress.js +2 -2
  93. package/dist/esm/components/Typography/Label/Label.js +2 -2
  94. package/dist/esm/components/Typography/Paragraph/Paragraph.js +2 -2
  95. package/dist/esm/components/form/Checkbox/{Group/Group.js → CheckboxGroup.js} +3 -2
  96. package/dist/esm/components/form/Checkbox/index.js +1 -1
  97. package/dist/esm/components/form/Checkbox/useCheckbox.js +1 -1
  98. package/dist/esm/components/form/Combobox/Combobox.js +2 -2
  99. package/dist/esm/components/form/Combobox/Custom.js +2 -2
  100. package/dist/esm/components/form/Combobox/Option/Description.js +1 -2
  101. package/dist/esm/components/form/Combobox/internal/ComboboxChips.js +1 -2
  102. package/dist/esm/components/form/Combobox/internal/ComboboxClearButton.js +1 -2
  103. package/dist/esm/components/form/Combobox/internal/ComboboxError.js +1 -2
  104. package/dist/esm/components/form/Combobox/internal/ComboboxInput.js +5 -6
  105. package/dist/esm/components/form/Combobox/internal/ComboboxLabel.js +1 -2
  106. package/dist/esm/components/form/Combobox/internal/ComboboxNative.js +1 -2
  107. package/dist/esm/components/form/Combobox/useCombobox.js +5 -0
  108. package/dist/esm/components/form/Combobox/useFloatingCombobox.js +2 -2
  109. package/dist/esm/components/form/NativeSelect/NativeSelect.js +2 -2
  110. package/dist/esm/components/form/NativeSelect/useNativeSelect.js +19 -1
  111. package/dist/esm/components/form/Radio/{Group/Group.js → RadioGroup.js} +3 -3
  112. package/dist/esm/components/form/Radio/index.js +1 -1
  113. package/dist/esm/components/form/Radio/useRadio.js +1 -1
  114. package/dist/esm/components/form/Switch/useSwitch.js +1 -1
  115. package/dist/esm/index.js +9 -2
  116. package/dist/esm/node_modules/@floating-ui/core/dist/floating-ui.core.js +24 -10
  117. package/dist/esm/node_modules/@floating-ui/dom/dist/floating-ui.dom.js +41 -26
  118. package/dist/esm/node_modules/@floating-ui/react/dist/floating-ui.react.js +830 -712
  119. package/dist/esm/node_modules/@floating-ui/react/dist/floating-ui.react.utils.js +1 -1
  120. package/dist/esm/node_modules/@floating-ui/react/node_modules/@floating-ui/utils/dist/floating-ui.utils.dom.js +57 -0
  121. package/dist/esm/node_modules/@floating-ui/react/node_modules/@floating-ui/utils/dist/floating-ui.utils.js +9 -0
  122. package/dist/esm/node_modules/@floating-ui/react-dom/dist/floating-ui.react-dom.js +96 -45
  123. package/dist/esm/node_modules/@floating-ui/utils/dist/floating-ui.utils.dom.js +17 -7
  124. package/dist/esm/node_modules/@floating-ui/utils/dist/floating-ui.utils.js +14 -5
  125. package/dist/esm/node_modules/@radix-ui/react-compose-refs/dist/index.js +10 -14
  126. package/dist/esm/node_modules/@radix-ui/react-slot/dist/index.js +71 -71
  127. package/dist/esm/node_modules/@tanstack/virtual-core/dist/esm/index.js +134 -62
  128. package/dist/esm/node_modules/@tanstack/virtual-core/dist/esm/utils.js +3 -5
  129. package/dist/esm/utilities/AnimateHeight/AnimateHeight.js +4 -1
  130. package/dist/esm/utilities/RovingFocus/RovingFocusItem.js +36 -8
  131. package/dist/esm/utilities/RovingFocus/RovingFocusRoot.js +5 -3
  132. package/dist/esm/utilities/RovingFocus/useRovingFocus.js +2 -1
  133. package/dist/types/components/Accordion/AccordionHeading.d.ts +1 -1
  134. package/dist/types/components/Accordion/AccordionHeading.d.ts.map +1 -1
  135. package/dist/types/components/Accordion/AccordionItem.d.ts +2 -2
  136. package/dist/types/components/Accordion/AccordionItem.d.ts.map +1 -1
  137. package/dist/types/components/Accordion/AccordionRoot.d.ts +2 -2
  138. package/dist/types/components/Accordion/AccordionRoot.d.ts.map +1 -1
  139. package/dist/types/components/Accordion/index.d.ts +2 -2
  140. package/dist/types/components/Accordion/index.d.ts.map +1 -1
  141. package/dist/types/components/Alert/Alert.d.ts +3 -3
  142. package/dist/types/components/Alert/Alert.d.ts.map +1 -1
  143. package/dist/types/components/Badge/Badge.d.ts +93 -0
  144. package/dist/types/components/Badge/Badge.d.ts.map +1 -0
  145. package/dist/types/components/Badge/index.d.ts +3 -0
  146. package/dist/types/components/Badge/index.d.ts.map +1 -0
  147. package/dist/types/components/Box/Box.d.ts +5 -5
  148. package/dist/types/components/Box/Box.d.ts.map +1 -1
  149. package/dist/types/components/Breadcrumbs/BreadcrumbsItem.d.ts +4 -0
  150. package/dist/types/components/Breadcrumbs/BreadcrumbsItem.d.ts.map +1 -0
  151. package/dist/types/components/Breadcrumbs/BreadcrumbsLink.d.ts +10 -0
  152. package/dist/types/components/Breadcrumbs/BreadcrumbsLink.d.ts.map +1 -0
  153. package/dist/types/components/Breadcrumbs/BreadcrumbsList.d.ts +4 -0
  154. package/dist/types/components/Breadcrumbs/BreadcrumbsList.d.ts.map +1 -0
  155. package/dist/types/components/Breadcrumbs/BreadcrumbsNav.d.ts +14 -0
  156. package/dist/types/components/Breadcrumbs/BreadcrumbsNav.d.ts.map +1 -0
  157. package/dist/types/components/Breadcrumbs/BreadcrumbsRoot.d.ts +16 -0
  158. package/dist/types/components/Breadcrumbs/BreadcrumbsRoot.d.ts.map +1 -0
  159. package/dist/types/components/Breadcrumbs/index.d.ts +44 -0
  160. package/dist/types/components/Breadcrumbs/index.d.ts.map +1 -0
  161. package/dist/types/components/Button/Button.d.ts +6 -6
  162. package/dist/types/components/Button/Button.d.ts.map +1 -1
  163. package/dist/types/components/Card/Card.d.ts +3 -3
  164. package/dist/types/components/Card/Card.d.ts.map +1 -1
  165. package/dist/types/components/Card/CardContent.d.ts +1 -1
  166. package/dist/types/components/Card/CardContent.d.ts.map +1 -1
  167. package/dist/types/components/Card/CardFooter.d.ts +1 -1
  168. package/dist/types/components/Card/CardFooter.d.ts.map +1 -1
  169. package/dist/types/components/Card/CardHeader.d.ts +1 -1
  170. package/dist/types/components/Card/CardHeader.d.ts.map +1 -1
  171. package/dist/types/components/Card/CardMedia.d.ts +1 -1
  172. package/dist/types/components/Card/CardMedia.d.ts.map +1 -1
  173. package/dist/types/components/Card/index.d.ts.map +1 -1
  174. package/dist/types/components/Chip/Group/Group.d.ts +1 -1
  175. package/dist/types/components/Chip/Removable/Removable.d.ts +1 -1
  176. package/dist/types/components/Chip/Toggle/Toggle.d.ts +3 -3
  177. package/dist/types/components/Chip/Toggle/Toggle.d.ts.map +1 -1
  178. package/dist/types/components/Divider/Divider.d.ts +1 -1
  179. package/dist/types/components/Divider/Divider.d.ts.map +1 -1
  180. package/dist/types/components/DropdownMenu/DropdownMenuContent.d.ts.map +1 -1
  181. package/dist/types/components/DropdownMenu/DropdownMenuGroup.d.ts.map +1 -1
  182. package/dist/types/components/DropdownMenu/DropdownMenuTrigger.d.ts +7 -7
  183. package/dist/types/components/DropdownMenu/index.d.ts.map +1 -1
  184. package/dist/types/components/ErrorSummary/ErrorSummaryRoot.d.ts +1 -1
  185. package/dist/types/components/ErrorSummary/index.d.ts.map +1 -1
  186. package/dist/types/components/Link/Link.d.ts +4 -4
  187. package/dist/types/components/Link/Link.d.ts.map +1 -1
  188. package/dist/types/components/List/ListHeading.d.ts +4 -4
  189. package/dist/types/components/List/ListItem.d.ts +1 -1
  190. package/dist/types/components/List/ListItem.d.ts.map +1 -1
  191. package/dist/types/components/List/ListRoot.d.ts +2 -2
  192. package/dist/types/components/List/ListRoot.d.ts.map +1 -1
  193. package/dist/types/components/List/Lists.d.ts +2 -2
  194. package/dist/types/components/List/Lists.d.ts.map +1 -1
  195. package/dist/types/components/Modal/ModaContent.d.ts +1 -1
  196. package/dist/types/components/Modal/ModaContent.d.ts.map +1 -1
  197. package/dist/types/components/Modal/ModalDialog.d.ts +4 -4
  198. package/dist/types/components/Modal/ModalDialog.d.ts.map +1 -1
  199. package/dist/types/components/Modal/ModalFooter.d.ts +1 -1
  200. package/dist/types/components/Modal/ModalFooter.d.ts.map +1 -1
  201. package/dist/types/components/Modal/ModalHeader.d.ts +19 -3
  202. package/dist/types/components/Modal/ModalHeader.d.ts.map +1 -1
  203. package/dist/types/components/Modal/ModalTrigger.d.ts +7 -7
  204. package/dist/types/components/Modal/index.d.ts +1 -1
  205. package/dist/types/components/Modal/index.d.ts.map +1 -1
  206. package/dist/types/components/Modal/useModalState.d.ts.map +1 -1
  207. package/dist/types/components/Pagination/Pagination.d.ts +4 -4
  208. package/dist/types/components/Pagination/Pagination.d.ts.map +1 -1
  209. package/dist/types/components/Pagination/PaginationButton.d.ts +1 -1
  210. package/dist/types/components/Pagination/PaginationButton.d.ts.map +1 -1
  211. package/dist/types/components/Pagination/PaginationContent.d.ts +1 -1
  212. package/dist/types/components/Pagination/PaginationContent.d.ts.map +1 -1
  213. package/dist/types/components/Pagination/PaginationItem.d.ts +1 -1
  214. package/dist/types/components/Pagination/PaginationItem.d.ts.map +1 -1
  215. package/dist/types/components/Pagination/PaginationNextPrev.d.ts +2 -2
  216. package/dist/types/components/Pagination/PaginationRoot.d.ts +3 -3
  217. package/dist/types/components/Pagination/PaginationRoot.d.ts.map +1 -1
  218. package/dist/types/components/Pagination/index.d.ts.map +1 -1
  219. package/dist/types/components/Popover/PopoverContent.d.ts.map +1 -1
  220. package/dist/types/components/Popover/PopoverRoot.d.ts +10 -10
  221. package/dist/types/components/Popover/PopoverRoot.d.ts.map +1 -1
  222. package/dist/types/components/Popover/PopoverTrigger.d.ts +7 -7
  223. package/dist/types/components/Popover/index.d.ts.map +1 -1
  224. package/dist/types/components/SkipLink/SkipLink.d.ts.map +1 -1
  225. package/dist/types/components/Spinner/Spinner.d.ts.map +1 -1
  226. package/dist/types/components/Table/Table.d.ts +4 -4
  227. package/dist/types/components/Table/Table.d.ts.map +1 -1
  228. package/dist/types/components/Table/TableHeaderCell.d.ts +3 -3
  229. package/dist/types/components/Table/TableHeaderCell.d.ts.map +1 -1
  230. package/dist/types/components/Table/index.d.ts.map +1 -1
  231. package/dist/types/components/Tabs/TabList.d.ts.map +1 -1
  232. package/dist/types/components/Tabs/TabsRoot.d.ts +4 -4
  233. package/dist/types/components/Tabs/TabsRoot.d.ts.map +1 -1
  234. package/dist/types/components/Tag/Tag.d.ts +1 -1
  235. package/dist/types/components/Tag/Tag.d.ts.map +1 -1
  236. package/dist/types/components/ToggleGroup/ToggleGroupItem/ToggleGroupItem.d.ts +1 -1
  237. package/dist/types/components/ToggleGroup/ToggleGroupItem/ToggleGroupItem.d.ts.map +1 -1
  238. package/dist/types/components/ToggleGroup/ToggleGroupRoot.d.ts +5 -5
  239. package/dist/types/components/ToggleGroup/ToggleGroupRoot.d.ts.map +1 -1
  240. package/dist/types/components/ToggleGroup/index.d.ts.map +1 -1
  241. package/dist/types/components/Tooltip/Tooltip.d.ts +4 -4
  242. package/dist/types/components/Tooltip/Tooltip.d.ts.map +1 -1
  243. package/dist/types/components/Typography/ErrorMessage/ErrorMessage.d.ts +4 -4
  244. package/dist/types/components/Typography/ErrorMessage/ErrorMessage.d.ts.map +1 -1
  245. package/dist/types/components/Typography/Heading/Heading.d.ts +4 -4
  246. package/dist/types/components/Typography/Heading/Heading.d.ts.map +1 -1
  247. package/dist/types/components/Typography/Ingress/Ingress.d.ts +3 -3
  248. package/dist/types/components/Typography/Ingress/Ingress.d.ts.map +1 -1
  249. package/dist/types/components/Typography/Label/Label.d.ts +4 -4
  250. package/dist/types/components/Typography/Label/Label.d.ts.map +1 -1
  251. package/dist/types/components/Typography/Paragraph/Paragraph.d.ts +4 -4
  252. package/dist/types/components/Typography/Paragraph/Paragraph.d.ts.map +1 -1
  253. package/dist/types/components/form/CharacterCounter.d.ts.map +1 -1
  254. package/dist/types/components/form/Checkbox/Checkbox.d.ts +1 -1
  255. package/dist/types/components/form/Checkbox/Checkbox.d.ts.map +1 -1
  256. package/dist/types/components/form/Checkbox/{Group/Group.d.ts → CheckboxGroup.d.ts} +5 -5
  257. package/dist/types/components/form/Checkbox/CheckboxGroup.d.ts.map +1 -0
  258. package/dist/types/components/form/Checkbox/index.d.ts +2 -2
  259. package/dist/types/components/form/Checkbox/index.d.ts.map +1 -1
  260. package/dist/types/components/form/Combobox/Combobox.d.ts +42 -42
  261. package/dist/types/components/form/Combobox/Combobox.d.ts.map +1 -1
  262. package/dist/types/components/form/Combobox/ComboboxIdContext.d.ts.map +1 -1
  263. package/dist/types/components/form/Combobox/Empty.d.ts +1 -1
  264. package/dist/types/components/form/Combobox/Empty.d.ts.map +1 -1
  265. package/dist/types/components/form/Combobox/Option/Option.d.ts +2 -2
  266. package/dist/types/components/form/Combobox/Option/Option.d.ts.map +1 -1
  267. package/dist/types/components/form/Combobox/Option/useComboboxOption.d.ts +1 -1
  268. package/dist/types/components/form/Combobox/index.d.ts +3 -0
  269. package/dist/types/components/form/Combobox/index.d.ts.map +1 -1
  270. package/dist/types/components/form/Combobox/useCombobox.d.ts.map +1 -1
  271. package/dist/types/components/form/Combobox/useFloatingCombobox.d.ts +9 -9
  272. package/dist/types/components/form/Fieldset/Fieldset.d.ts +3 -3
  273. package/dist/types/components/form/Fieldset/Fieldset.d.ts.map +1 -1
  274. package/dist/types/components/form/Fieldset/useFieldset.d.ts +2 -2
  275. package/dist/types/components/form/NativeSelect/NativeSelect.d.ts +6 -6
  276. package/dist/types/components/form/NativeSelect/NativeSelect.d.ts.map +1 -1
  277. package/dist/types/components/form/NativeSelect/useNativeSelect.d.ts +1 -1
  278. package/dist/types/components/form/NativeSelect/useNativeSelect.d.ts.map +1 -1
  279. package/dist/types/components/form/Radio/{Group/Group.d.ts → RadioGroup.d.ts} +7 -7
  280. package/dist/types/components/form/Radio/RadioGroup.d.ts.map +1 -0
  281. package/dist/types/components/form/Radio/index.d.ts +2 -2
  282. package/dist/types/components/form/Radio/index.d.ts.map +1 -1
  283. package/dist/types/components/form/Radio/useRadio.d.ts.map +1 -1
  284. package/dist/types/components/form/Search/Search.d.ts +7 -7
  285. package/dist/types/components/form/Search/Search.d.ts.map +1 -1
  286. package/dist/types/components/form/Switch/Switch.d.ts +2 -2
  287. package/dist/types/components/form/Switch/Switch.d.ts.map +1 -1
  288. package/dist/types/components/form/Textarea/Textarea.d.ts +7 -7
  289. package/dist/types/components/form/Textarea/Textarea.d.ts.map +1 -1
  290. package/dist/types/components/form/Textfield/Textfield.d.ts +7 -7
  291. package/dist/types/components/form/Textfield/Textfield.d.ts.map +1 -1
  292. package/dist/types/components/index.d.ts +1 -0
  293. package/dist/types/components/index.d.ts.map +1 -1
  294. package/dist/types/utilities/AnimateHeight/AnimateHeight.d.ts.map +1 -1
  295. package/dist/types/utilities/RovingFocus/RovingFocusItem.d.ts +2 -2
  296. package/dist/types/utilities/RovingFocus/RovingFocusItem.d.ts.map +1 -1
  297. package/dist/types/utilities/RovingFocus/RovingFocusRoot.d.ts +10 -2
  298. package/dist/types/utilities/RovingFocus/RovingFocusRoot.d.ts.map +1 -1
  299. package/dist/types/utilities/RovingFocus/useRovingFocus.d.ts +11 -10
  300. package/dist/types/utilities/RovingFocus/useRovingFocus.d.ts.map +1 -1
  301. package/package.json +18 -8
  302. package/dist/cjs/node_modules/@babel/runtime/helpers/esm/extends.js +0 -19
  303. package/dist/esm/node_modules/@babel/runtime/helpers/esm/extends.js +0 -17
  304. package/dist/types/components/form/Checkbox/Group/Group.d.ts.map +0 -1
  305. package/dist/types/components/form/Checkbox/Group/index.d.ts +0 -2
  306. package/dist/types/components/form/Checkbox/Group/index.d.ts.map +0 -1
  307. package/dist/types/components/form/Radio/Group/Group.d.ts.map +0 -1
  308. package/dist/types/components/form/Radio/Group/index.d.ts +0 -2
  309. package/dist/types/components/form/Radio/Group/index.d.ts.map +0 -1
@@ -2,14 +2,13 @@
2
2
  import * as React from 'react';
3
3
  import { useLayoutEffect, useEffect, useRef } from 'react';
4
4
  import { getDocument, isMouseLikePointerType, isTypeableCombobox, activeElement, contains, isVirtualClick, isVirtualPointerEvent, getTarget, isSafari, isMac, isTypeableElement, stopEvent, isReactEvent, isRootElement, isEventTargetWithin } from './floating-ui.react.utils.js';
5
- import { floor } from '../../utils/dist/floating-ui.utils.js';
6
- import { useFloating as useFloating$1 } from '../../react-dom/dist/floating-ui.react-dom.js';
7
- export { arrow } from '../../react-dom/dist/floating-ui.react-dom.js';
8
- import { isElement, isHTMLElement, getOverflowAncestors, getWindow, getNodeName, isLastTraversableNode, getParentNode, getComputedStyle } from '../../utils/dist/floating-ui.utils.dom.js';
5
+ import { floor } from '../node_modules/@floating-ui/utils/dist/floating-ui.utils.js';
6
+ import { getComputedStyle, isElement, isHTMLElement, getWindow, getNodeName, isLastTraversableNode, getParentNode } from '../node_modules/@floating-ui/utils/dist/floating-ui.utils.dom.js';
9
7
  import { tabbable, isTabbable } from '../../../tabbable/dist/index.esm.js';
10
- import { createPortal } from 'react-dom';
11
- import { platform } from '../../dom/dist/floating-ui.dom.js';
12
- export { autoUpdate, computePosition, flip, shift, size } from '../../dom/dist/floating-ui.dom.js';
8
+ import * as ReactDOM from 'react-dom';
9
+ import { useFloating as useFloating$1 } from '../../react-dom/dist/floating-ui.react-dom.js';
10
+ export { arrow, flip, offset, shift, size } from '../../react-dom/dist/floating-ui.react-dom.js';
11
+ import { getOverflowAncestors } from '../../utils/dist/floating-ui.utils.dom.js';
13
12
 
14
13
  /**
15
14
  * Merges an array of refs into a single memoized callback ref or `null`.
@@ -87,14 +86,10 @@ function findNonDisabledIndex(listRef, _temp) {
87
86
  amount = 1
88
87
  } = _temp === void 0 ? {} : _temp;
89
88
  const list = listRef.current;
90
- const isDisabledIndex = disabledIndices ? index => disabledIndices.includes(index) : index => {
91
- const element = list[index];
92
- return element == null || element.hasAttribute('disabled') || element.getAttribute('aria-disabled') === 'true';
93
- };
94
89
  let index = startingIndex;
95
90
  do {
96
91
  index += decrement ? -amount : amount;
97
- } while (index >= 0 && index <= list.length - 1 && isDisabledIndex(index));
92
+ } while (index >= 0 && index <= list.length - 1 && isDisabled(list, index, disabledIndices));
98
93
  return index;
99
94
  }
100
95
  function getGridNavigatedIndex(elementsRef, _ref) {
@@ -190,8 +185,8 @@ function getGridNavigatedIndex(elementsRef, _ref) {
190
185
  if (prevIndex % cols !== 0) {
191
186
  nextIndex = findNonDisabledIndex(elementsRef, {
192
187
  startingIndex: prevIndex,
193
- disabledIndices,
194
- decrement: true
188
+ decrement: true,
189
+ disabledIndices
195
190
  });
196
191
  if (loop && isDifferentRow(nextIndex, cols, prevRow)) {
197
192
  nextIndex = findNonDisabledIndex(elementsRef, {
@@ -270,13 +265,20 @@ function buildCellMap(sizes, cols, dense) {
270
265
  function getCellIndexOfCorner(index, sizes, cellMap, cols, corner) {
271
266
  if (index === -1) return -1;
272
267
  const firstCellIndex = cellMap.indexOf(index);
268
+ const sizeItem = sizes[index];
273
269
  switch (corner) {
274
270
  case 'tl':
275
271
  return firstCellIndex;
276
272
  case 'tr':
277
- return firstCellIndex + sizes[index].width - 1;
273
+ if (!sizeItem) {
274
+ return firstCellIndex;
275
+ }
276
+ return firstCellIndex + sizeItem.width - 1;
278
277
  case 'bl':
279
- return firstCellIndex + (sizes[index].height - 1) * cols;
278
+ if (!sizeItem) {
279
+ return firstCellIndex;
280
+ }
281
+ return firstCellIndex + (sizeItem.height - 1) * cols;
280
282
  case 'br':
281
283
  return cellMap.lastIndexOf(index);
282
284
  }
@@ -286,6 +288,13 @@ function getCellIndexOfCorner(index, sizes, cellMap, cols, corner) {
286
288
  function getCellIndices(indices, cellMap) {
287
289
  return cellMap.flatMap((index, cellIndex) => indices.includes(index) ? [cellIndex] : []);
288
290
  }
291
+ function isDisabled(list, index, disabledIndices) {
292
+ if (disabledIndices) {
293
+ return disabledIndices.includes(index);
294
+ }
295
+ const element = list[index];
296
+ return element == null || element.hasAttribute('disabled') || element.getAttribute('aria-disabled') === 'true';
297
+ }
289
298
 
290
299
  let rafId = 0;
291
300
  function enqueueFocus(el, options) {
@@ -416,6 +425,16 @@ const FloatingArrow = /*#__PURE__*/React.forwardRef(function FloatingArrow(props
416
425
  }
417
426
  }
418
427
  const clipPathId = useId();
428
+ const [isRTL, setIsRTL] = React.useState(false);
429
+
430
+ // https://github.com/floating-ui/floating-ui/issues/2932
431
+ index(() => {
432
+ if (!floating) return;
433
+ const isRTL = getComputedStyle(floating).direction === 'rtl';
434
+ if (isRTL) {
435
+ setIsRTL(true);
436
+ }
437
+ }, [floating]);
419
438
  if (!floating) {
420
439
  return null;
421
440
  }
@@ -427,7 +446,6 @@ const FloatingArrow = /*#__PURE__*/React.forwardRef(function FloatingArrow(props
427
446
  const svgX = width / 2 * (tipRadius / -8 + 1);
428
447
  const svgY = height / 2 * tipRadius / 4;
429
448
  const [side, alignment] = placement.split('-');
430
- const isRTL = platform.isRTL(floating);
431
449
  const isCustomShape = !!d;
432
450
  const isVerticalSide = side === 'top' || side === 'bottom';
433
451
  const yOffsetProp = staticOffset && alignment === 'end' ? 'bottom' : 'top';
@@ -550,11 +568,7 @@ function useHover(context, props) {
550
568
  onOpenChange,
551
569
  dataRef,
552
570
  events,
553
- elements: {
554
- domReference,
555
- floating
556
- },
557
- refs
571
+ elements
558
572
  } = context;
559
573
  const {
560
574
  enabled = true,
@@ -568,10 +582,11 @@ function useHover(context, props) {
568
582
  const parentId = useFloatingParentNodeId();
569
583
  const handleCloseRef = useLatestRef(handleClose);
570
584
  const delayRef = useLatestRef(delay);
585
+ const openRef = useLatestRef(open);
571
586
  const pointerTypeRef = React.useRef();
572
- const timeoutRef = React.useRef();
587
+ const timeoutRef = React.useRef(-1);
573
588
  const handlerRef = React.useRef();
574
- const restTimeoutRef = React.useRef();
589
+ const restTimeoutRef = React.useRef(-1);
575
590
  const blockMouseMoveRef = React.useRef(true);
576
591
  const performedPointerEventsMutationRef = React.useRef(false);
577
592
  const unbindMouseMoveRef = React.useRef(() => {});
@@ -584,9 +599,7 @@ function useHover(context, props) {
584
599
  // When closing before opening, clear the delay timeouts to cancel it
585
600
  // from showing.
586
601
  React.useEffect(() => {
587
- if (!enabled) {
588
- return;
589
- }
602
+ if (!enabled) return;
590
603
  function onOpenChange(_ref) {
591
604
  let {
592
605
  open
@@ -603,20 +616,20 @@ function useHover(context, props) {
603
616
  };
604
617
  }, [enabled, events]);
605
618
  React.useEffect(() => {
606
- if (!enabled || !handleCloseRef.current || !open) {
607
- return;
608
- }
619
+ if (!enabled) return;
620
+ if (!handleCloseRef.current) return;
621
+ if (!open) return;
609
622
  function onLeave(event) {
610
623
  if (isHoverOpen()) {
611
624
  onOpenChange(false, event, 'hover');
612
625
  }
613
626
  }
614
- const html = getDocument(floating).documentElement;
627
+ const html = getDocument(elements.floating).documentElement;
615
628
  html.addEventListener('mouseleave', onLeave);
616
629
  return () => {
617
630
  html.removeEventListener('mouseleave', onLeave);
618
631
  };
619
- }, [floating, open, onOpenChange, enabled, handleCloseRef, isHoverOpen]);
632
+ }, [elements.floating, open, onOpenChange, enabled, handleCloseRef, isHoverOpen]);
620
633
  const closeWithDelay = React.useCallback(function (event, runElseBranch, reason) {
621
634
  if (runElseBranch === void 0) {
622
635
  runElseBranch = true;
@@ -627,64 +640,62 @@ function useHover(context, props) {
627
640
  const closeDelay = getDelay(delayRef.current, 'close', pointerTypeRef.current);
628
641
  if (closeDelay && !handlerRef.current) {
629
642
  clearTimeout(timeoutRef.current);
630
- timeoutRef.current = setTimeout(() => onOpenChange(false, event, reason), closeDelay);
643
+ timeoutRef.current = window.setTimeout(() => onOpenChange(false, event, reason), closeDelay);
631
644
  } else if (runElseBranch) {
632
645
  clearTimeout(timeoutRef.current);
633
646
  onOpenChange(false, event, reason);
634
647
  }
635
648
  }, [delayRef, onOpenChange]);
636
- const cleanupMouseMoveHandler = React.useCallback(() => {
649
+ const cleanupMouseMoveHandler = useEffectEvent(() => {
637
650
  unbindMouseMoveRef.current();
638
651
  handlerRef.current = undefined;
639
- }, []);
640
- const clearPointerEvents = React.useCallback(() => {
652
+ });
653
+ const clearPointerEvents = useEffectEvent(() => {
641
654
  if (performedPointerEventsMutationRef.current) {
642
- const body = getDocument(refs.floating.current).body;
655
+ const body = getDocument(elements.floating).body;
643
656
  body.style.pointerEvents = '';
644
657
  body.removeAttribute(safePolygonIdentifier);
645
658
  performedPointerEventsMutationRef.current = false;
646
659
  }
647
- }, [refs]);
660
+ });
648
661
 
649
662
  // Registering the mouse events on the reference directly to bypass React's
650
663
  // delegation system. If the cursor was on a disabled element and then entered
651
664
  // the reference (no gap), `mouseenter` doesn't fire in the delegation system.
652
665
  React.useEffect(() => {
653
- if (!enabled) {
654
- return;
655
- }
666
+ if (!enabled) return;
656
667
  function isClickLikeOpenEvent() {
657
668
  return dataRef.current.openEvent ? ['click', 'mousedown'].includes(dataRef.current.openEvent.type) : false;
658
669
  }
659
670
  function onMouseEnter(event) {
660
671
  clearTimeout(timeoutRef.current);
661
672
  blockMouseMoveRef.current = false;
662
- if (mouseOnly && !isMouseLikePointerType(pointerTypeRef.current) || restMs > 0 && getDelay(delayRef.current, 'open') === 0) {
673
+ if (mouseOnly && !isMouseLikePointerType(pointerTypeRef.current) || restMs > 0 && !getDelay(delayRef.current, 'open')) {
663
674
  return;
664
675
  }
665
676
  const openDelay = getDelay(delayRef.current, 'open', pointerTypeRef.current);
666
677
  if (openDelay) {
667
- timeoutRef.current = setTimeout(() => {
668
- onOpenChange(true, event, 'hover');
678
+ timeoutRef.current = window.setTimeout(() => {
679
+ if (!openRef.current) {
680
+ onOpenChange(true, event, 'hover');
681
+ }
669
682
  }, openDelay);
670
683
  } else {
671
684
  onOpenChange(true, event, 'hover');
672
685
  }
673
686
  }
674
687
  function onMouseLeave(event) {
675
- if (isClickLikeOpenEvent()) {
676
- return;
677
- }
688
+ if (isClickLikeOpenEvent()) return;
678
689
  unbindMouseMoveRef.current();
679
- const doc = getDocument(floating);
690
+ const doc = getDocument(elements.floating);
680
691
  clearTimeout(restTimeoutRef.current);
681
- if (handleCloseRef.current) {
692
+ if (handleCloseRef.current && dataRef.current.floatingContext) {
682
693
  // Prevent clearing `onScrollMouseLeave` timeout.
683
694
  if (!open) {
684
695
  clearTimeout(timeoutRef.current);
685
696
  }
686
697
  handlerRef.current = handleCloseRef.current({
687
- ...context,
698
+ ...dataRef.current.floatingContext,
688
699
  tree,
689
700
  x: event.clientX,
690
701
  y: event.clientY,
@@ -705,7 +716,7 @@ function useHover(context, props) {
705
716
  // Allow interactivity without `safePolygon` on touch devices. With a
706
717
  // pointer, a short close delay is an alternative, so it should work
707
718
  // consistently.
708
- const shouldClose = pointerTypeRef.current === 'touch' ? !contains(floating, event.relatedTarget) : true;
719
+ const shouldClose = pointerTypeRef.current === 'touch' ? !contains(elements.floating, event.relatedTarget) : true;
709
720
  if (shouldClose) {
710
721
  closeWithDelay(event);
711
722
  }
@@ -715,11 +726,10 @@ function useHover(context, props) {
715
726
  // did not move.
716
727
  // https://github.com/floating-ui/floating-ui/discussions/1692
717
728
  function onScrollMouseLeave(event) {
718
- if (isClickLikeOpenEvent()) {
719
- return;
720
- }
729
+ if (isClickLikeOpenEvent()) return;
730
+ if (!dataRef.current.floatingContext) return;
721
731
  handleCloseRef.current == null || handleCloseRef.current({
722
- ...context,
732
+ ...dataRef.current.floatingContext,
723
733
  tree,
724
734
  x: event.clientX,
725
735
  y: event.clientY,
@@ -730,24 +740,26 @@ function useHover(context, props) {
730
740
  }
731
741
  })(event);
732
742
  }
733
- if (isElement(domReference)) {
734
- const ref = domReference;
743
+ if (isElement(elements.domReference)) {
744
+ var _elements$floating;
745
+ const ref = elements.domReference;
735
746
  open && ref.addEventListener('mouseleave', onScrollMouseLeave);
736
- floating == null || floating.addEventListener('mouseleave', onScrollMouseLeave);
747
+ (_elements$floating = elements.floating) == null || _elements$floating.addEventListener('mouseleave', onScrollMouseLeave);
737
748
  move && ref.addEventListener('mousemove', onMouseEnter, {
738
749
  once: true
739
750
  });
740
751
  ref.addEventListener('mouseenter', onMouseEnter);
741
752
  ref.addEventListener('mouseleave', onMouseLeave);
742
753
  return () => {
754
+ var _elements$floating2;
743
755
  open && ref.removeEventListener('mouseleave', onScrollMouseLeave);
744
- floating == null || floating.removeEventListener('mouseleave', onScrollMouseLeave);
756
+ (_elements$floating2 = elements.floating) == null || _elements$floating2.removeEventListener('mouseleave', onScrollMouseLeave);
745
757
  move && ref.removeEventListener('mousemove', onMouseEnter);
746
758
  ref.removeEventListener('mouseenter', onMouseEnter);
747
759
  ref.removeEventListener('mouseleave', onMouseLeave);
748
760
  };
749
761
  }
750
- }, [domReference, floating, enabled, context, mouseOnly, restMs, move, closeWithDelay, cleanupMouseMoveHandler, clearPointerEvents, onOpenChange, open, tree, delayRef, handleCloseRef, dataRef]);
762
+ }, [elements, enabled, context, mouseOnly, restMs, move, closeWithDelay, cleanupMouseMoveHandler, clearPointerEvents, onOpenChange, open, openRef, tree, delayRef, handleCloseRef, dataRef]);
751
763
 
752
764
  // Block pointer-events of every element other than the reference and floating
753
765
  // while the floating element is open and has a `handleClose` handler. Also
@@ -755,30 +767,29 @@ function useHover(context, props) {
755
767
  // https://github.com/floating-ui/floating-ui/issues/1722
756
768
  index(() => {
757
769
  var _handleCloseRef$curre;
758
- if (!enabled) {
759
- return;
760
- }
770
+ if (!enabled) return;
761
771
  if (open && (_handleCloseRef$curre = handleCloseRef.current) != null && _handleCloseRef$curre.__options.blockPointerEvents && isHoverOpen()) {
762
- const body = getDocument(floating).body;
772
+ const body = getDocument(elements.floating).body;
763
773
  body.setAttribute(safePolygonIdentifier, '');
764
774
  body.style.pointerEvents = 'none';
765
775
  performedPointerEventsMutationRef.current = true;
766
- if (isElement(domReference) && floating) {
776
+ const floatingEl = elements.floating;
777
+ if (isElement(elements.domReference) && floatingEl) {
767
778
  var _tree$nodesRef$curren;
768
- const ref = domReference;
779
+ const ref = elements.domReference;
769
780
  const parentFloating = tree == null || (_tree$nodesRef$curren = tree.nodesRef.current.find(node => node.id === parentId)) == null || (_tree$nodesRef$curren = _tree$nodesRef$curren.context) == null ? void 0 : _tree$nodesRef$curren.elements.floating;
770
781
  if (parentFloating) {
771
782
  parentFloating.style.pointerEvents = '';
772
783
  }
773
784
  ref.style.pointerEvents = 'auto';
774
- floating.style.pointerEvents = 'auto';
785
+ floatingEl.style.pointerEvents = 'auto';
775
786
  return () => {
776
787
  ref.style.pointerEvents = '';
777
- floating.style.pointerEvents = '';
788
+ floatingEl.style.pointerEvents = '';
778
789
  };
779
790
  }
780
791
  }
781
- }, [enabled, open, parentId, floating, domReference, tree, handleCloseRef, isHoverOpen]);
792
+ }, [enabled, open, parentId, elements, tree, handleCloseRef, isHoverOpen]);
782
793
  index(() => {
783
794
  if (!open) {
784
795
  pointerTypeRef.current = undefined;
@@ -793,48 +804,50 @@ function useHover(context, props) {
793
804
  clearTimeout(restTimeoutRef.current);
794
805
  clearPointerEvents();
795
806
  };
796
- }, [enabled, domReference, cleanupMouseMoveHandler, clearPointerEvents]);
797
- return React.useMemo(() => {
798
- if (!enabled) {
799
- return {};
800
- }
807
+ }, [enabled, elements.domReference, cleanupMouseMoveHandler, clearPointerEvents]);
808
+ const reference = React.useMemo(() => {
801
809
  function setPointerRef(event) {
802
810
  pointerTypeRef.current = event.pointerType;
803
811
  }
804
812
  return {
805
- reference: {
806
- onPointerDown: setPointerRef,
807
- onPointerEnter: setPointerRef,
808
- onMouseMove(event) {
809
- function handleMouseMove() {
810
- if (!blockMouseMoveRef.current) {
811
- onOpenChange(true, event.nativeEvent, 'hover');
812
- }
813
- }
814
- if (mouseOnly && !isMouseLikePointerType(pointerTypeRef.current)) {
815
- return;
816
- }
817
- if (open || restMs === 0) {
818
- return;
819
- }
820
- clearTimeout(restTimeoutRef.current);
821
- if (pointerTypeRef.current === 'touch') {
822
- handleMouseMove();
823
- } else {
824
- restTimeoutRef.current = setTimeout(handleMouseMove, restMs);
813
+ onPointerDown: setPointerRef,
814
+ onPointerEnter: setPointerRef,
815
+ onMouseMove(event) {
816
+ const {
817
+ nativeEvent
818
+ } = event;
819
+ function handleMouseMove() {
820
+ if (!blockMouseMoveRef.current && !openRef.current) {
821
+ onOpenChange(true, nativeEvent, 'hover');
825
822
  }
826
823
  }
827
- },
828
- floating: {
829
- onMouseEnter() {
830
- clearTimeout(timeoutRef.current);
831
- },
832
- onMouseLeave(event) {
833
- closeWithDelay(event.nativeEvent, false);
824
+ if (mouseOnly && !isMouseLikePointerType(pointerTypeRef.current)) {
825
+ return;
826
+ }
827
+ if (open || restMs === 0) {
828
+ return;
829
+ }
830
+ clearTimeout(restTimeoutRef.current);
831
+ if (pointerTypeRef.current === 'touch') {
832
+ handleMouseMove();
833
+ } else {
834
+ restTimeoutRef.current = window.setTimeout(handleMouseMove, restMs);
834
835
  }
835
836
  }
836
837
  };
837
- }, [enabled, mouseOnly, open, restMs, onOpenChange, closeWithDelay]);
838
+ }, [mouseOnly, onOpenChange, open, openRef, restMs]);
839
+ const floating = React.useMemo(() => ({
840
+ onMouseEnter() {
841
+ clearTimeout(timeoutRef.current);
842
+ },
843
+ onMouseLeave(event) {
844
+ closeWithDelay(event.nativeEvent, false);
845
+ }
846
+ }), [closeWithDelay]);
847
+ return React.useMemo(() => enabled ? {
848
+ reference,
849
+ floating
850
+ } : {}, [enabled, reference, floating]);
838
851
  }
839
852
 
840
853
  function getAncestors(nodes, id) {
@@ -929,7 +942,8 @@ function applyAttributeToOthers(uncorrectedAvoidElements, body, ariaHidden, iner
929
942
  if (!parent || elementsToStop.has(parent)) {
930
943
  return;
931
944
  }
932
- Array.prototype.forEach.call(parent.children, node => {
945
+ [].forEach.call(parent.children, node => {
946
+ if (getNodeName(node) === 'script') return;
933
947
  if (elementsToKeep.has(node)) {
934
948
  deep(node);
935
949
  } else {
@@ -1036,6 +1050,32 @@ function enableFocusInside(container) {
1036
1050
  }
1037
1051
  });
1038
1052
  }
1053
+ function getClosestTabbableElement(tabbableElements, element, floating) {
1054
+ const elementIndex = tabbableElements.indexOf(element);
1055
+ function traverseTabbableElements(next) {
1056
+ const attr = createAttribute('focus-guard');
1057
+ let index = elementIndex + (next ? 1 : 0);
1058
+ let currentElement = tabbableElements[index];
1059
+ while (currentElement && (!currentElement.isConnected || currentElement.hasAttribute(attr) || contains(floating, currentElement))) {
1060
+ if (next) {
1061
+ index++;
1062
+ } else {
1063
+ index--;
1064
+ }
1065
+ currentElement = tabbableElements[index];
1066
+ }
1067
+ return currentElement;
1068
+ }
1069
+
1070
+ // First, try to find the next tabbable element
1071
+ const next = traverseTabbableElements(true);
1072
+ if (next) {
1073
+ return next;
1074
+ }
1075
+
1076
+ // If we can't find a next tabbable element, try to find the previous one
1077
+ return traverseTabbableElements(false);
1078
+ }
1039
1079
 
1040
1080
  // See Diego Haz's Sandbox for making this logic work well on Safari/iOS:
1041
1081
  // https://codesandbox.io/s/tabbable-portal-f4tng?file=/src/FocusTrap.tsx
@@ -1090,7 +1130,6 @@ const FocusGuard = /*#__PURE__*/React.forwardRef(function FocusGuard(props, ref)
1090
1130
 
1091
1131
  const PortalContext = /*#__PURE__*/React.createContext(null);
1092
1132
  const attr = /*#__PURE__*/createAttribute('portal');
1093
-
1094
1133
  /**
1095
1134
  * @see https://floating-ui.com/docs/FloatingPortal#usefloatingportalnode
1096
1135
  */
@@ -1118,6 +1157,10 @@ function useFloatingPortalNode(props) {
1118
1157
  };
1119
1158
  }, [portalNode]);
1120
1159
  index(() => {
1160
+ // Wait for the uniqueId to be generated before creating the portal node in
1161
+ // React <18 (using `useFloatingId` instead of the native `useId`).
1162
+ // https://github.com/floating-ui/floating-ui/issues/2778
1163
+ if (!uniqueId) return;
1121
1164
  if (portalNodeRef.current) return;
1122
1165
  const existingIdRoot = id ? document.getElementById(id) : null;
1123
1166
  if (!existingIdRoot) return;
@@ -1129,6 +1172,7 @@ function useFloatingPortalNode(props) {
1129
1172
  setPortalNode(subRoot);
1130
1173
  }, [id, uniqueId]);
1131
1174
  index(() => {
1175
+ if (!uniqueId) return;
1132
1176
  if (portalNodeRef.current) return;
1133
1177
  let container = root || (portalContext == null ? void 0 : portalContext.portalNode);
1134
1178
  if (container && !isElement(container)) container = container.current;
@@ -1232,7 +1276,7 @@ function FloatingPortal(props) {
1232
1276
  }), shouldRenderGuards && portalNode && /*#__PURE__*/React.createElement("span", {
1233
1277
  "aria-owns": portalNode.id,
1234
1278
  style: HIDDEN_STYLES
1235
- }), portalNode && /*#__PURE__*/createPortal(children, portalNode), shouldRenderGuards && portalNode && /*#__PURE__*/React.createElement(FocusGuard, {
1279
+ }), portalNode && /*#__PURE__*/ReactDOM.createPortal(children, portalNode), shouldRenderGuards && portalNode && /*#__PURE__*/React.createElement(FocusGuard, {
1236
1280
  "data-type": "outside",
1237
1281
  ref: afterOutsideRef,
1238
1282
  onFocus: event => {
@@ -1257,8 +1301,9 @@ function addPreviouslyFocusedElement(element) {
1257
1301
  if (!tabbableEl || getNodeName(tabbableEl) === 'body') return;
1258
1302
  if (!isTabbable(tabbableEl, getTabbableOptions())) {
1259
1303
  const tabbableChild = tabbable(tabbableEl, getTabbableOptions())[0];
1260
- if (!tabbableChild) return;
1261
- tabbableEl = tabbableChild;
1304
+ if (tabbableChild) {
1305
+ tabbableEl = tabbableChild;
1306
+ }
1262
1307
  }
1263
1308
  previouslyFocusedElements.push(tabbableEl);
1264
1309
  if (previouslyFocusedElements.length > LIST_LIMIT) {
@@ -1289,6 +1334,7 @@ function FloatingFocusManager(props) {
1289
1334
  guards: _guards = true,
1290
1335
  initialFocus = 0,
1291
1336
  returnFocus = true,
1337
+ restoreFocus = false,
1292
1338
  modal = true,
1293
1339
  visuallyHiddenDismiss = false,
1294
1340
  closeOnFocusOut = true
@@ -1300,6 +1346,7 @@ function FloatingFocusManager(props) {
1300
1346
  onOpenChange,
1301
1347
  events,
1302
1348
  dataRef,
1349
+ floatingId,
1303
1350
  elements: {
1304
1351
  domReference,
1305
1352
  floating
@@ -1324,31 +1371,37 @@ function FloatingFocusManager(props) {
1324
1371
  const endDismissButtonRef = React.useRef(null);
1325
1372
  const preventReturnFocusRef = React.useRef(false);
1326
1373
  const isPointerDownRef = React.useRef(false);
1374
+ const tabbableIndexRef = React.useRef(-1);
1327
1375
  const isInsidePortal = portalContext != null;
1328
- const getTabbableContent = React.useCallback(function (container) {
1376
+ const firstElementChild = floating == null ? void 0 : floating.firstElementChild;
1377
+ // If the floating element is acting as a positioning wrapper rather than the
1378
+ // element that receives aria props, use it as the focus root instead.
1379
+ const floatingFocusNode = (firstElementChild == null ? void 0 : firstElementChild.id) === floatingId ? firstElementChild : floating;
1380
+ const getTabbableContent = useEffectEvent(function (container) {
1329
1381
  if (container === void 0) {
1330
- container = floating;
1382
+ container = floatingFocusNode;
1331
1383
  }
1332
1384
  return container ? tabbable(container, getTabbableOptions()) : [];
1333
- }, [floating]);
1334
- const getTabbableElements = React.useCallback(container => {
1385
+ });
1386
+ const getTabbableElements = useEffectEvent(container => {
1335
1387
  const content = getTabbableContent(container);
1336
1388
  return orderRef.current.map(type => {
1337
1389
  if (domReference && type === 'reference') {
1338
1390
  return domReference;
1339
1391
  }
1340
- if (floating && type === 'floating') {
1341
- return floating;
1392
+ if (floatingFocusNode && type === 'floating') {
1393
+ return floatingFocusNode;
1342
1394
  }
1343
1395
  return content;
1344
1396
  }).filter(Boolean).flat();
1345
- }, [domReference, floating, orderRef, getTabbableContent]);
1397
+ });
1346
1398
  React.useEffect(() => {
1347
- if (disabled || !modal) return;
1399
+ if (disabled) return;
1400
+ if (!modal) return;
1348
1401
  function onKeyDown(event) {
1349
1402
  if (event.key === 'Tab') {
1350
1403
  // The focus guards have nothing to focus, so we need to stop the event.
1351
- if (contains(floating, activeElement(getDocument(floating))) && getTabbableContent().length === 0 && !isUntrappedTypeableCombobox) {
1404
+ if (contains(floatingFocusNode, activeElement(getDocument(floatingFocusNode))) && getTabbableContent().length === 0 && !isUntrappedTypeableCombobox) {
1352
1405
  stopEvent(event);
1353
1406
  }
1354
1407
  const els = getTabbableElements();
@@ -1361,20 +1414,37 @@ function FloatingFocusManager(props) {
1361
1414
  enqueueFocus(els[1]);
1362
1415
  }
1363
1416
  }
1364
- if (orderRef.current[1] === 'floating' && target === floating && event.shiftKey) {
1417
+ if (orderRef.current[1] === 'floating' && target === floatingFocusNode && event.shiftKey) {
1365
1418
  stopEvent(event);
1366
1419
  enqueueFocus(els[0]);
1367
1420
  }
1368
1421
  }
1369
1422
  }
1370
- const doc = getDocument(floating);
1423
+ const doc = getDocument(floatingFocusNode);
1371
1424
  doc.addEventListener('keydown', onKeyDown);
1372
1425
  return () => {
1373
1426
  doc.removeEventListener('keydown', onKeyDown);
1374
1427
  };
1375
- }, [disabled, domReference, floating, modal, orderRef, isUntrappedTypeableCombobox, getTabbableContent, getTabbableElements]);
1428
+ }, [disabled, domReference, floatingFocusNode, modal, orderRef, isUntrappedTypeableCombobox, getTabbableContent, getTabbableElements]);
1429
+ React.useEffect(() => {
1430
+ if (disabled) return;
1431
+ if (!floating) return;
1432
+ function handleFocusIn(event) {
1433
+ const target = getTarget(event);
1434
+ const tabbableContent = getTabbableContent();
1435
+ const tabbableIndex = tabbableContent.indexOf(target);
1436
+ if (tabbableIndex !== -1) {
1437
+ tabbableIndexRef.current = tabbableIndex;
1438
+ }
1439
+ }
1440
+ floating.addEventListener('focusin', handleFocusIn);
1441
+ return () => {
1442
+ floating.removeEventListener('focusin', handleFocusIn);
1443
+ };
1444
+ }, [disabled, floating, getTabbableContent]);
1376
1445
  React.useEffect(() => {
1377
- if (disabled || !closeOnFocusOut) return;
1446
+ if (disabled) return;
1447
+ if (!closeOnFocusOut) return;
1378
1448
 
1379
1449
  // In Safari, buttons lose focus when pressing them.
1380
1450
  function handlePointerDown() {
@@ -1394,9 +1464,25 @@ function FloatingFocusManager(props) {
1394
1464
  return ((_node$context3 = node.context) == null ? void 0 : _node$context3.elements.floating) === relatedTarget || ((_node$context4 = node.context) == null ? void 0 : _node$context4.elements.domReference) === relatedTarget;
1395
1465
  })));
1396
1466
 
1467
+ // Restore focus to the previous tabbable element index to prevent
1468
+ // focus from being lost outside the floating tree.
1469
+ if (restoreFocus && movedToUnrelatedNode && activeElement(getDocument(floatingFocusNode)) === getDocument(floatingFocusNode).body) {
1470
+ // Let `FloatingPortal` effect knows that focus is still inside the
1471
+ // floating tree.
1472
+ if (isHTMLElement(floatingFocusNode)) {
1473
+ floatingFocusNode == null || floatingFocusNode.focus();
1474
+ }
1475
+ const prevTabbableIndex = tabbableIndexRef.current;
1476
+ const tabbableContent = getTabbableContent();
1477
+ const nodeToFocus = tabbableContent[prevTabbableIndex] || tabbableContent[tabbableContent.length - 1] || floatingFocusNode;
1478
+ if (isHTMLElement(nodeToFocus)) {
1479
+ nodeToFocus.focus();
1480
+ }
1481
+ }
1482
+
1397
1483
  // Focus did not move inside the floating tree, and there are no tabbable
1398
1484
  // portal guards to handle closing.
1399
- if (relatedTarget && movedToUnrelatedNode && !isPointerDownRef.current &&
1485
+ if ((isUntrappedTypeableCombobox ? true : !modal) && relatedTarget && movedToUnrelatedNode && !isPointerDownRef.current &&
1400
1486
  // Fix React 18 Strict Mode returnFocus due to double rendering.
1401
1487
  relatedTarget !== getPreviouslyFocusedElement()) {
1402
1488
  preventReturnFocusRef.current = true;
@@ -1407,14 +1493,14 @@ function FloatingFocusManager(props) {
1407
1493
  if (floating && isHTMLElement(domReference)) {
1408
1494
  domReference.addEventListener('focusout', handleFocusOutside);
1409
1495
  domReference.addEventListener('pointerdown', handlePointerDown);
1410
- !modal && floating.addEventListener('focusout', handleFocusOutside);
1496
+ floating.addEventListener('focusout', handleFocusOutside);
1411
1497
  return () => {
1412
1498
  domReference.removeEventListener('focusout', handleFocusOutside);
1413
1499
  domReference.removeEventListener('pointerdown', handlePointerDown);
1414
- !modal && floating.removeEventListener('focusout', handleFocusOutside);
1500
+ floating.removeEventListener('focusout', handleFocusOutside);
1415
1501
  };
1416
1502
  }
1417
- }, [disabled, domReference, floating, modal, nodeId, tree, portalContext, onOpenChange, closeOnFocusOut]);
1503
+ }, [disabled, domReference, floating, floatingFocusNode, modal, nodeId, tree, portalContext, onOpenChange, closeOnFocusOut, restoreFocus, getTabbableContent, isUntrappedTypeableCombobox]);
1418
1504
  React.useEffect(() => {
1419
1505
  var _portalContext$portal;
1420
1506
  if (disabled) return;
@@ -1430,39 +1516,45 @@ function FloatingFocusManager(props) {
1430
1516
  }
1431
1517
  }, [disabled, domReference, floating, modal, orderRef, portalContext, isUntrappedTypeableCombobox, guards]);
1432
1518
  index(() => {
1433
- if (disabled || !floating) return;
1434
- const doc = getDocument(floating);
1519
+ if (disabled || !isHTMLElement(floatingFocusNode)) return;
1520
+ const doc = getDocument(floatingFocusNode);
1435
1521
  const previouslyFocusedElement = activeElement(doc);
1436
1522
 
1437
1523
  // Wait for any layout effect state setters to execute to set `tabIndex`.
1438
1524
  queueMicrotask(() => {
1439
- const focusableElements = getTabbableElements(floating);
1525
+ const focusableElements = getTabbableElements(floatingFocusNode);
1440
1526
  const initialFocusValue = initialFocusRef.current;
1441
- const elToFocus = (typeof initialFocusValue === 'number' ? focusableElements[initialFocusValue] : initialFocusValue.current) || floating;
1442
- const focusAlreadyInsideFloatingEl = contains(floating, previouslyFocusedElement);
1527
+ const elToFocus = (typeof initialFocusValue === 'number' ? focusableElements[initialFocusValue] : initialFocusValue.current) || floatingFocusNode;
1528
+ const focusAlreadyInsideFloatingEl = contains(floatingFocusNode, previouslyFocusedElement);
1443
1529
  if (!ignoreInitialFocus && !focusAlreadyInsideFloatingEl && open) {
1444
1530
  enqueueFocus(elToFocus, {
1445
- preventScroll: elToFocus === floating
1531
+ preventScroll: elToFocus === floatingFocusNode
1446
1532
  });
1447
1533
  }
1448
1534
  });
1449
- }, [disabled, open, floating, ignoreInitialFocus, getTabbableElements, initialFocusRef]);
1535
+ }, [disabled, open, floatingFocusNode, ignoreInitialFocus, getTabbableElements, initialFocusRef]);
1450
1536
  index(() => {
1451
- if (disabled || !floating) return;
1537
+ if (disabled || !floatingFocusNode) return;
1452
1538
  let preventReturnFocusScroll = false;
1453
- const doc = getDocument(floating);
1539
+ const doc = getDocument(floatingFocusNode);
1454
1540
  const previouslyFocusedElement = activeElement(doc);
1455
1541
  const contextData = dataRef.current;
1542
+ let openEvent = contextData.openEvent;
1543
+ const domReference = refs.domReference.current;
1456
1544
  addPreviouslyFocusedElement(previouslyFocusedElement);
1457
1545
 
1458
1546
  // Dismissing via outside press should always ignore `returnFocus` to
1459
1547
  // prevent unwanted scrolling.
1460
1548
  function onOpenChange(_ref) {
1461
1549
  let {
1550
+ open,
1462
1551
  reason,
1463
1552
  event,
1464
1553
  nested
1465
1554
  } = _ref;
1555
+ if (open) {
1556
+ openEvent = event;
1557
+ }
1466
1558
  if (reason === 'escape-key' && refs.domReference.current) {
1467
1559
  addPreviouslyFocusedElement(refs.domReference.current);
1468
1560
  }
@@ -1485,34 +1577,40 @@ function FloatingFocusManager(props) {
1485
1577
  var _node$context5;
1486
1578
  return contains((_node$context5 = node.context) == null ? void 0 : _node$context5.elements.floating, activeEl);
1487
1579
  });
1488
- const shouldFocusReference = isFocusInsideFloatingTree || contextData.openEvent && ['click', 'mousedown'].includes(contextData.openEvent.type);
1580
+ const shouldFocusReference = isFocusInsideFloatingTree || openEvent && ['click', 'mousedown'].includes(openEvent.type);
1489
1581
  if (shouldFocusReference && refs.domReference.current) {
1490
1582
  addPreviouslyFocusedElement(refs.domReference.current);
1491
1583
  }
1492
- const returnElement = getPreviouslyFocusedElement();
1493
- if (
1494
- // eslint-disable-next-line react-hooks/exhaustive-deps
1495
- returnFocusRef.current && !preventReturnFocusRef.current && isHTMLElement(returnElement) && (
1496
- // If the focus moved somewhere else after mount, avoid returning focus
1497
- // since it likely entered a different element which should be
1498
- // respected: https://github.com/floating-ui/floating-ui/issues/2607
1499
- returnElement !== activeEl && activeEl !== doc.body ? isFocusInsideFloatingTree : true)) {
1500
- enqueueFocus(returnElement, {
1501
- // When dismissing nested floating elements, by the time the rAF has
1502
- // executed, the menus will all have been unmounted. When they try
1503
- // to get focused, the calls get ignored — leaving the root
1504
- // reference focused as desired.
1505
- cancelPrevious: false,
1506
- preventScroll: preventReturnFocusScroll
1507
- });
1508
- }
1584
+ const returnContextElement = domReference || previouslyFocusedElement;
1585
+ const tabbableElements = tabbable(getDocument(returnContextElement).body, getTabbableOptions());
1586
+
1587
+ // Wait for the return element to get potentially disconnected before
1588
+ // checking.
1589
+ queueMicrotask(() => {
1590
+ let returnElement = getPreviouslyFocusedElement();
1591
+ if (!returnElement && isHTMLElement(returnContextElement) && floating) {
1592
+ returnElement = getClosestTabbableElement(tabbableElements, returnContextElement, floating);
1593
+ }
1594
+ if (
1595
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1596
+ returnFocusRef.current && !preventReturnFocusRef.current && isHTMLElement(returnElement) && (
1597
+ // If the focus moved somewhere else after mount, avoid returning focus
1598
+ // since it likely entered a different element which should be
1599
+ // respected: https://github.com/floating-ui/floating-ui/issues/2607
1600
+ returnElement !== activeEl && activeEl !== doc.body ? isFocusInsideFloatingTree : true)) {
1601
+ returnElement.focus({
1602
+ preventScroll: preventReturnFocusScroll
1603
+ });
1604
+ }
1605
+ });
1509
1606
  };
1510
- }, [disabled, floating, returnFocusRef, dataRef, refs, events, tree, nodeId]);
1607
+ }, [disabled, floating, floatingFocusNode, returnFocusRef, dataRef, refs, events, tree, nodeId]);
1511
1608
 
1512
1609
  // Synchronize the `context` & `modal` value to the FloatingPortal context.
1513
1610
  // It will decide whether or not it needs to render its own guards.
1514
1611
  index(() => {
1515
- if (disabled || !portalContext) return;
1612
+ if (disabled) return;
1613
+ if (!portalContext) return;
1516
1614
  portalContext.setFocusManagerState({
1517
1615
  modal,
1518
1616
  closeOnFocusOut,
@@ -1525,22 +1623,29 @@ function FloatingFocusManager(props) {
1525
1623
  };
1526
1624
  }, [disabled, portalContext, modal, open, onOpenChange, refs, closeOnFocusOut]);
1527
1625
  index(() => {
1528
- if (disabled || !floating || typeof MutationObserver !== 'function' || ignoreInitialFocus) {
1529
- return;
1530
- }
1626
+ if (disabled) return;
1627
+ if (!floatingFocusNode) return;
1628
+ if (typeof MutationObserver !== 'function') return;
1629
+ if (ignoreInitialFocus) return;
1531
1630
  const handleMutation = () => {
1532
- const tabIndex = floating.getAttribute('tabindex');
1533
- if (orderRef.current.includes('floating') || activeElement(getDocument(floating)) !== refs.domReference.current && getTabbableContent().length === 0) {
1631
+ const tabIndex = floatingFocusNode.getAttribute('tabindex');
1632
+ const tabbableContent = getTabbableContent();
1633
+ const activeEl = activeElement(getDocument(floating));
1634
+ const tabbableIndex = tabbableContent.indexOf(activeEl);
1635
+ if (tabbableIndex !== -1) {
1636
+ tabbableIndexRef.current = tabbableIndex;
1637
+ }
1638
+ if (orderRef.current.includes('floating') || activeEl !== refs.domReference.current && tabbableContent.length === 0) {
1534
1639
  if (tabIndex !== '0') {
1535
- floating.setAttribute('tabindex', '0');
1640
+ floatingFocusNode.setAttribute('tabindex', '0');
1536
1641
  }
1537
1642
  } else if (tabIndex !== '-1') {
1538
- floating.setAttribute('tabindex', '-1');
1643
+ floatingFocusNode.setAttribute('tabindex', '-1');
1539
1644
  }
1540
1645
  };
1541
1646
  handleMutation();
1542
1647
  const observer = new MutationObserver(handleMutation);
1543
- observer.observe(floating, {
1648
+ observer.observe(floatingFocusNode, {
1544
1649
  childList: true,
1545
1650
  subtree: true,
1546
1651
  attributes: true
@@ -1548,7 +1653,7 @@ function FloatingFocusManager(props) {
1548
1653
  return () => {
1549
1654
  observer.disconnect();
1550
1655
  };
1551
- }, [disabled, floating, refs, orderRef, getTabbableContent, ignoreInitialFocus]);
1656
+ }, [disabled, floating, floatingFocusNode, refs, orderRef, getTabbableContent, ignoreInitialFocus]);
1552
1657
  function renderDismissButton(location) {
1553
1658
  if (disabled || !visuallyHiddenDismiss || !modal) {
1554
1659
  return null;
@@ -1558,7 +1663,7 @@ function FloatingFocusManager(props) {
1558
1663
  onClick: event => onOpenChange(false, event.nativeEvent)
1559
1664
  }, typeof visuallyHiddenDismiss === 'string' ? visuallyHiddenDismiss : 'Dismiss');
1560
1665
  }
1561
- const shouldRenderGuards = !disabled && guards && (isInsidePortal || modal);
1666
+ const shouldRenderGuards = !disabled && guards && (modal ? !isUntrappedTypeableCombobox : true) && (isInsidePortal || modal);
1562
1667
  return /*#__PURE__*/React.createElement(React.Fragment, null, shouldRenderGuards && /*#__PURE__*/React.createElement(FocusGuard, {
1563
1668
  "data-type": "inside",
1564
1669
  ref: portalContext == null ? void 0 : portalContext.beforeInsideRef,
@@ -1630,81 +1735,74 @@ function useClick(context, props) {
1630
1735
  } = props;
1631
1736
  const pointerTypeRef = React.useRef();
1632
1737
  const didKeyDownRef = React.useRef(false);
1633
- return React.useMemo(() => {
1634
- if (!enabled) return {};
1635
- return {
1636
- reference: {
1637
- onPointerDown(event) {
1638
- pointerTypeRef.current = event.pointerType;
1639
- },
1640
- onMouseDown(event) {
1641
- // Ignore all buttons except for the "main" button.
1642
- // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button
1643
- if (event.button !== 0) {
1644
- return;
1645
- }
1646
- if (isMouseLikePointerType(pointerTypeRef.current, true) && ignoreMouse) {
1647
- return;
1648
- }
1649
- if (eventOption === 'click') {
1650
- return;
1651
- }
1652
- if (open && toggle && (dataRef.current.openEvent ? dataRef.current.openEvent.type === 'mousedown' : true)) {
1653
- onOpenChange(false, event.nativeEvent, 'click');
1654
- } else {
1655
- // Prevent stealing focus from the floating element
1656
- event.preventDefault();
1657
- onOpenChange(true, event.nativeEvent, 'click');
1658
- }
1659
- },
1660
- onClick(event) {
1661
- if (eventOption === 'mousedown' && pointerTypeRef.current) {
1662
- pointerTypeRef.current = undefined;
1663
- return;
1664
- }
1665
- if (isMouseLikePointerType(pointerTypeRef.current, true) && ignoreMouse) {
1666
- return;
1667
- }
1668
- if (open && toggle && (dataRef.current.openEvent ? dataRef.current.openEvent.type === 'click' : true)) {
1669
- onOpenChange(false, event.nativeEvent, 'click');
1670
- } else {
1671
- onOpenChange(true, event.nativeEvent, 'click');
1672
- }
1673
- },
1674
- onKeyDown(event) {
1675
- pointerTypeRef.current = undefined;
1676
- if (event.defaultPrevented || !keyboardHandlers || isButtonTarget(event)) {
1677
- return;
1678
- }
1679
- if (event.key === ' ' && !isSpaceIgnored(domReference)) {
1680
- // Prevent scrolling
1681
- event.preventDefault();
1682
- didKeyDownRef.current = true;
1683
- }
1684
- if (event.key === 'Enter') {
1685
- if (open && toggle) {
1686
- onOpenChange(false, event.nativeEvent, 'click');
1687
- } else {
1688
- onOpenChange(true, event.nativeEvent, 'click');
1689
- }
1690
- }
1691
- },
1692
- onKeyUp(event) {
1693
- if (event.defaultPrevented || !keyboardHandlers || isButtonTarget(event) || isSpaceIgnored(domReference)) {
1694
- return;
1695
- }
1696
- if (event.key === ' ' && didKeyDownRef.current) {
1697
- didKeyDownRef.current = false;
1698
- if (open && toggle) {
1699
- onOpenChange(false, event.nativeEvent, 'click');
1700
- } else {
1701
- onOpenChange(true, event.nativeEvent, 'click');
1702
- }
1703
- }
1738
+ const reference = React.useMemo(() => ({
1739
+ onPointerDown(event) {
1740
+ pointerTypeRef.current = event.pointerType;
1741
+ },
1742
+ onMouseDown(event) {
1743
+ const pointerType = pointerTypeRef.current;
1744
+
1745
+ // Ignore all buttons except for the "main" button.
1746
+ // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button
1747
+ if (event.button !== 0) return;
1748
+ if (eventOption === 'click') return;
1749
+ if (isMouseLikePointerType(pointerType, true) && ignoreMouse) return;
1750
+ if (open && toggle && (dataRef.current.openEvent ? dataRef.current.openEvent.type === 'mousedown' : true)) {
1751
+ onOpenChange(false, event.nativeEvent, 'click');
1752
+ } else {
1753
+ // Prevent stealing focus from the floating element
1754
+ event.preventDefault();
1755
+ onOpenChange(true, event.nativeEvent, 'click');
1756
+ }
1757
+ },
1758
+ onClick(event) {
1759
+ const pointerType = pointerTypeRef.current;
1760
+ if (eventOption === 'mousedown' && pointerTypeRef.current) {
1761
+ pointerTypeRef.current = undefined;
1762
+ return;
1763
+ }
1764
+ if (isMouseLikePointerType(pointerType, true) && ignoreMouse) return;
1765
+ if (open && toggle && (dataRef.current.openEvent ? dataRef.current.openEvent.type === 'click' : true)) {
1766
+ onOpenChange(false, event.nativeEvent, 'click');
1767
+ } else {
1768
+ onOpenChange(true, event.nativeEvent, 'click');
1769
+ }
1770
+ },
1771
+ onKeyDown(event) {
1772
+ pointerTypeRef.current = undefined;
1773
+ if (event.defaultPrevented || !keyboardHandlers || isButtonTarget(event)) {
1774
+ return;
1775
+ }
1776
+ if (event.key === ' ' && !isSpaceIgnored(domReference)) {
1777
+ // Prevent scrolling
1778
+ event.preventDefault();
1779
+ didKeyDownRef.current = true;
1780
+ }
1781
+ if (event.key === 'Enter') {
1782
+ if (open && toggle) {
1783
+ onOpenChange(false, event.nativeEvent, 'click');
1784
+ } else {
1785
+ onOpenChange(true, event.nativeEvent, 'click');
1704
1786
  }
1705
1787
  }
1706
- };
1707
- }, [enabled, dataRef, eventOption, ignoreMouse, keyboardHandlers, domReference, toggle, open, onOpenChange]);
1788
+ },
1789
+ onKeyUp(event) {
1790
+ if (event.defaultPrevented || !keyboardHandlers || isButtonTarget(event) || isSpaceIgnored(domReference)) {
1791
+ return;
1792
+ }
1793
+ if (event.key === ' ' && didKeyDownRef.current) {
1794
+ didKeyDownRef.current = false;
1795
+ if (open && toggle) {
1796
+ onOpenChange(false, event.nativeEvent, 'click');
1797
+ } else {
1798
+ onOpenChange(true, event.nativeEvent, 'click');
1799
+ }
1800
+ }
1801
+ }
1802
+ }), [dataRef, domReference, eventOption, ignoreMouse, keyboardHandlers, onOpenChange, open, toggle]);
1803
+ return React.useMemo(() => enabled ? {
1804
+ reference
1805
+ } : {}, [enabled, reference]);
1708
1806
  }
1709
1807
 
1710
1808
  const bubbleHandlerKeys = {
@@ -1736,12 +1834,7 @@ function useDismiss(context, props) {
1736
1834
  const {
1737
1835
  open,
1738
1836
  onOpenChange,
1739
- nodeId,
1740
- elements: {
1741
- reference,
1742
- domReference,
1743
- floating
1744
- },
1837
+ elements,
1745
1838
  dataRef
1746
1839
  } = context;
1747
1840
  const {
@@ -1769,9 +1862,11 @@ function useDismiss(context, props) {
1769
1862
  outsidePress: outsidePressCapture
1770
1863
  } = normalizeProp(capture);
1771
1864
  const closeOnEscapeKeyDown = useEffectEvent(event => {
1865
+ var _dataRef$current$floa;
1772
1866
  if (!open || !enabled || !escapeKey || event.key !== 'Escape') {
1773
1867
  return;
1774
1868
  }
1869
+ const nodeId = (_dataRef$current$floa = dataRef.current.floatingContext) == null ? void 0 : _dataRef$current$floa.nodeId;
1775
1870
  const children = tree ? getChildren(tree.nodesRef.current, nodeId) : [];
1776
1871
  if (!escapeKeyBubbles) {
1777
1872
  event.stopPropagation();
@@ -1801,6 +1896,7 @@ function useDismiss(context, props) {
1801
1896
  (_getTarget2 = getTarget(event)) == null || _getTarget2.addEventListener('keydown', callback);
1802
1897
  });
1803
1898
  const closeOnPressOutside = useEffectEvent(event => {
1899
+ var _dataRef$current$floa2;
1804
1900
  // Given developers can stop the propagation of the synthetic event,
1805
1901
  // we can only be confident with a positive value.
1806
1902
  const insideReactTree = insideReactTreeRef.current;
@@ -1823,7 +1919,7 @@ function useDismiss(context, props) {
1823
1919
  }
1824
1920
  const target = getTarget(event);
1825
1921
  const inertSelector = "[" + createAttribute('inert') + "]";
1826
- const markers = getDocument(floating).querySelectorAll(inertSelector);
1922
+ const markers = getDocument(elements.floating).querySelectorAll(inertSelector);
1827
1923
  let targetRootAncestor = isElement(target) ? target : null;
1828
1924
  while (targetRootAncestor && !isLastTraversableNode(targetRootAncestor)) {
1829
1925
  const nextParent = getParentNode(targetRootAncestor);
@@ -1837,7 +1933,7 @@ function useDismiss(context, props) {
1837
1933
  // floating element rendered.
1838
1934
  if (markers.length && isElement(target) && !isRootElement(target) &&
1839
1935
  // Clicked on a direct ancestor (e.g. FloatingOverlay).
1840
- !contains(target, floating) &&
1936
+ !contains(target, elements.floating) &&
1841
1937
  // If the target root element contains none of the markers, then the
1842
1938
  // element was injected after the floating element rendered.
1843
1939
  Array.from(markers).every(marker => !contains(targetRootAncestor, marker))) {
@@ -1866,11 +1962,12 @@ function useDismiss(context, props) {
1866
1962
  return;
1867
1963
  }
1868
1964
  }
1965
+ const nodeId = (_dataRef$current$floa2 = dataRef.current.floatingContext) == null ? void 0 : _dataRef$current$floa2.nodeId;
1869
1966
  const targetIsInsideChildren = tree && getChildren(tree.nodesRef.current, nodeId).some(node => {
1870
1967
  var _node$context;
1871
1968
  return isEventTargetWithin(event, (_node$context = node.context) == null ? void 0 : _node$context.elements.floating);
1872
1969
  });
1873
- if (isEventTargetWithin(event, floating) || isEventTargetWithin(event, domReference) || targetIsInsideChildren) {
1970
+ if (isEventTargetWithin(event, elements.floating) || isEventTargetWithin(event, elements.domReference) || targetIsInsideChildren) {
1874
1971
  return;
1875
1972
  }
1876
1973
  const children = tree ? getChildren(tree.nodesRef.current, nodeId) : [];
@@ -1907,19 +2004,19 @@ function useDismiss(context, props) {
1907
2004
  function onScroll(event) {
1908
2005
  onOpenChange(false, event, 'ancestor-scroll');
1909
2006
  }
1910
- const doc = getDocument(floating);
2007
+ const doc = getDocument(elements.floating);
1911
2008
  escapeKey && doc.addEventListener('keydown', escapeKeyCapture ? closeOnEscapeKeyDownCapture : closeOnEscapeKeyDown, escapeKeyCapture);
1912
2009
  outsidePress && doc.addEventListener(outsidePressEvent, outsidePressCapture ? closeOnPressOutsideCapture : closeOnPressOutside, outsidePressCapture);
1913
2010
  let ancestors = [];
1914
2011
  if (ancestorScroll) {
1915
- if (isElement(domReference)) {
1916
- ancestors = getOverflowAncestors(domReference);
2012
+ if (isElement(elements.domReference)) {
2013
+ ancestors = getOverflowAncestors(elements.domReference);
1917
2014
  }
1918
- if (isElement(floating)) {
1919
- ancestors = ancestors.concat(getOverflowAncestors(floating));
2015
+ if (isElement(elements.floating)) {
2016
+ ancestors = ancestors.concat(getOverflowAncestors(elements.floating));
1920
2017
  }
1921
- if (!isElement(reference) && reference && reference.contextElement) {
1922
- ancestors = ancestors.concat(getOverflowAncestors(reference.contextElement));
2018
+ if (!isElement(elements.reference) && elements.reference && elements.reference.contextElement) {
2019
+ ancestors = ancestors.concat(getOverflowAncestors(elements.reference.contextElement));
1923
2020
  }
1924
2021
  }
1925
2022
 
@@ -1940,37 +2037,80 @@ function useDismiss(context, props) {
1940
2037
  ancestor.removeEventListener('scroll', onScroll);
1941
2038
  });
1942
2039
  };
1943
- }, [dataRef, floating, domReference, reference, escapeKey, outsidePress, outsidePressEvent, open, onOpenChange, ancestorScroll, enabled, escapeKeyBubbles, outsidePressBubbles, closeOnEscapeKeyDown, escapeKeyCapture, closeOnEscapeKeyDownCapture, closeOnPressOutside, outsidePressCapture, closeOnPressOutsideCapture]);
2040
+ }, [dataRef, elements, escapeKey, outsidePress, outsidePressEvent, open, onOpenChange, ancestorScroll, enabled, escapeKeyBubbles, outsidePressBubbles, closeOnEscapeKeyDown, escapeKeyCapture, closeOnEscapeKeyDownCapture, closeOnPressOutside, outsidePressCapture, closeOnPressOutsideCapture]);
1944
2041
  React.useEffect(() => {
1945
2042
  insideReactTreeRef.current = false;
1946
2043
  }, [outsidePress, outsidePressEvent]);
1947
- return React.useMemo(() => {
1948
- if (!enabled) {
1949
- return {};
2044
+ const reference = React.useMemo(() => ({
2045
+ onKeyDown: closeOnEscapeKeyDown,
2046
+ [bubbleHandlerKeys[referencePressEvent]]: event => {
2047
+ if (referencePress) {
2048
+ onOpenChange(false, event.nativeEvent, 'reference-press');
2049
+ }
2050
+ }
2051
+ }), [closeOnEscapeKeyDown, onOpenChange, referencePress, referencePressEvent]);
2052
+ const floating = React.useMemo(() => ({
2053
+ onKeyDown: closeOnEscapeKeyDown,
2054
+ onMouseDown() {
2055
+ endedOrStartedInsideRef.current = true;
2056
+ },
2057
+ onMouseUp() {
2058
+ endedOrStartedInsideRef.current = true;
2059
+ },
2060
+ [captureHandlerKeys[outsidePressEvent]]: () => {
2061
+ insideReactTreeRef.current = true;
2062
+ }
2063
+ }), [closeOnEscapeKeyDown, outsidePressEvent]);
2064
+ return React.useMemo(() => enabled ? {
2065
+ reference,
2066
+ floating
2067
+ } : {}, [enabled, reference, floating]);
2068
+ }
2069
+
2070
+ function useFloatingRootContext(options) {
2071
+ const {
2072
+ open = false,
2073
+ onOpenChange: onOpenChangeProp,
2074
+ elements: elementsProp
2075
+ } = options;
2076
+ const floatingId = useId();
2077
+ const dataRef = React.useRef({});
2078
+ const [events] = React.useState(() => createPubSub());
2079
+ const nested = useFloatingParentNodeId() != null;
2080
+ if (process.env.NODE_ENV !== "production") {
2081
+ const optionDomReference = elementsProp.reference;
2082
+ if (optionDomReference && !isElement(optionDomReference)) {
2083
+ error('Cannot pass a virtual element to the `elements.reference` option,', 'as it must be a real DOM element. Use `refs.setPositionReference()`', 'instead.');
1950
2084
  }
1951
- return {
1952
- reference: {
1953
- onKeyDown: closeOnEscapeKeyDown,
1954
- [bubbleHandlerKeys[referencePressEvent]]: event => {
1955
- if (referencePress) {
1956
- onOpenChange(false, event.nativeEvent, 'reference-press');
1957
- }
1958
- }
1959
- },
1960
- floating: {
1961
- onKeyDown: closeOnEscapeKeyDown,
1962
- onMouseDown() {
1963
- endedOrStartedInsideRef.current = true;
1964
- },
1965
- onMouseUp() {
1966
- endedOrStartedInsideRef.current = true;
1967
- },
1968
- [captureHandlerKeys[outsidePressEvent]]: () => {
1969
- insideReactTreeRef.current = true;
1970
- }
1971
- }
1972
- };
1973
- }, [enabled, referencePress, outsidePressEvent, referencePressEvent, onOpenChange, closeOnEscapeKeyDown]);
2085
+ }
2086
+ const [positionReference, setPositionReference] = React.useState(elementsProp.reference);
2087
+ const onOpenChange = useEffectEvent((open, event, reason) => {
2088
+ dataRef.current.openEvent = open ? event : undefined;
2089
+ events.emit('openchange', {
2090
+ open,
2091
+ event,
2092
+ reason,
2093
+ nested
2094
+ });
2095
+ onOpenChangeProp == null || onOpenChangeProp(open, event, reason);
2096
+ });
2097
+ const refs = React.useMemo(() => ({
2098
+ setPositionReference
2099
+ }), []);
2100
+ const elements = React.useMemo(() => ({
2101
+ reference: positionReference || elementsProp.reference || null,
2102
+ floating: elementsProp.floating || null,
2103
+ domReference: elementsProp.reference
2104
+ }), [positionReference, elementsProp.reference, elementsProp.floating]);
2105
+ return React.useMemo(() => ({
2106
+ dataRef,
2107
+ open,
2108
+ onOpenChange,
2109
+ elements,
2110
+ events,
2111
+ floatingId,
2112
+ refs
2113
+ }), [open, onOpenChange, elements, events, floatingId, refs]);
1974
2114
  }
1975
2115
 
1976
2116
  /**
@@ -1978,24 +2118,28 @@ function useDismiss(context, props) {
1978
2118
  * @see https://floating-ui.com/docs/useFloating
1979
2119
  */
1980
2120
  function useFloating(options) {
1981
- var _options$elements;
1982
2121
  if (options === void 0) {
1983
2122
  options = {};
1984
2123
  }
1985
2124
  const {
1986
- open = false,
1987
- onOpenChange: unstable_onOpenChange,
1988
2125
  nodeId
1989
2126
  } = options;
2127
+ const internalRootContext = useFloatingRootContext({
2128
+ ...options,
2129
+ elements: {
2130
+ reference: null,
2131
+ floating: null,
2132
+ ...options.elements
2133
+ }
2134
+ });
2135
+ const rootContext = options.rootContext || internalRootContext;
2136
+ const computedElements = rootContext.elements;
1990
2137
  const [_domReference, setDomReference] = React.useState(null);
1991
2138
  const [positionReference, _setPositionReference] = React.useState(null);
1992
- const optionDomReference = (_options$elements = options.elements) == null ? void 0 : _options$elements.reference;
2139
+ const optionDomReference = computedElements == null ? void 0 : computedElements.reference;
1993
2140
  const domReference = optionDomReference || _domReference;
1994
- if (process.env.NODE_ENV !== "production") {
1995
- if (optionDomReference && !isElement(optionDomReference)) {
1996
- error('Cannot pass a virtual element to the `elements.reference` option,', 'as it must be a real DOM element. Use `refs.setPositionReference()`', 'instead.');
1997
- }
1998
- }
2141
+ const domReferenceRef = React.useRef(null);
2142
+ const tree = useFloatingTree();
1999
2143
  index(() => {
2000
2144
  if (domReference) {
2001
2145
  domReferenceRef.current = domReference;
@@ -2004,28 +2148,12 @@ function useFloating(options) {
2004
2148
  const position = useFloating$1({
2005
2149
  ...options,
2006
2150
  elements: {
2007
- ...options.elements,
2151
+ ...computedElements,
2008
2152
  ...(positionReference && {
2009
2153
  reference: positionReference
2010
2154
  })
2011
2155
  }
2012
2156
  });
2013
- const tree = useFloatingTree();
2014
- const nested = useFloatingParentNodeId() != null;
2015
- const onOpenChange = useEffectEvent((open, event, reason) => {
2016
- dataRef.current.openEvent = open ? event : undefined;
2017
- events.emit('openchange', {
2018
- open,
2019
- event,
2020
- reason,
2021
- nested
2022
- });
2023
- unstable_onOpenChange == null || unstable_onOpenChange(open, event, reason);
2024
- });
2025
- const domReferenceRef = React.useRef(null);
2026
- const dataRef = React.useRef({});
2027
- const events = React.useState(() => createPubSub())[0];
2028
- const floatingId = useId();
2029
2157
  const setPositionReference = React.useCallback(node => {
2030
2158
  const computedPositionReference = isElement(node) ? {
2031
2159
  getBoundingClientRect: () => node.getBoundingClientRect(),
@@ -2064,16 +2192,13 @@ function useFloating(options) {
2064
2192
  }), [position.elements, domReference]);
2065
2193
  const context = React.useMemo(() => ({
2066
2194
  ...position,
2195
+ ...rootContext,
2067
2196
  refs,
2068
2197
  elements,
2069
- dataRef,
2070
- nodeId,
2071
- floatingId,
2072
- events,
2073
- open,
2074
- onOpenChange
2075
- }), [position, nodeId, floatingId, events, open, onOpenChange, refs, elements]);
2198
+ nodeId
2199
+ }), [position, refs, elements, nodeId, rootContext]);
2076
2200
  index(() => {
2201
+ rootContext.dataRef.current.floatingContext = context;
2077
2202
  const node = tree == null ? void 0 : tree.nodesRef.current.find(node => node.id === nodeId);
2078
2203
  if (node) {
2079
2204
  node.context = context;
@@ -2100,10 +2225,8 @@ function useFocus(context, props) {
2100
2225
  open,
2101
2226
  onOpenChange,
2102
2227
  events,
2103
- refs,
2104
- elements: {
2105
- domReference
2106
- }
2228
+ dataRef,
2229
+ elements
2107
2230
  } = context;
2108
2231
  const {
2109
2232
  enabled = true,
@@ -2113,16 +2236,14 @@ function useFocus(context, props) {
2113
2236
  const timeoutRef = React.useRef();
2114
2237
  const keyboardModalityRef = React.useRef(true);
2115
2238
  React.useEffect(() => {
2116
- if (!enabled) {
2117
- return;
2118
- }
2119
- const win = getWindow(domReference);
2239
+ if (!enabled) return;
2240
+ const win = getWindow(elements.domReference);
2120
2241
 
2121
2242
  // If the reference was focused and the user left the tab/window, and the
2122
2243
  // floating element was not open, the focus should be blocked when they
2123
2244
  // return to the tab/window.
2124
2245
  function onBlur() {
2125
- if (!open && isHTMLElement(domReference) && domReference === activeElement(getDocument(domReference))) {
2246
+ if (!open && isHTMLElement(elements.domReference) && elements.domReference === activeElement(getDocument(elements.domReference))) {
2126
2247
  blockFocusRef.current = true;
2127
2248
  }
2128
2249
  }
@@ -2135,11 +2256,9 @@ function useFocus(context, props) {
2135
2256
  win.removeEventListener('blur', onBlur);
2136
2257
  win.removeEventListener('keydown', onKeyDown, true);
2137
2258
  };
2138
- }, [domReference, open, enabled]);
2259
+ }, [elements.domReference, open, enabled]);
2139
2260
  React.useEffect(() => {
2140
- if (!enabled) {
2141
- return;
2142
- }
2261
+ if (!enabled) return;
2143
2262
  function onOpenChange(_ref) {
2144
2263
  let {
2145
2264
  reason
@@ -2158,69 +2277,67 @@ function useFocus(context, props) {
2158
2277
  clearTimeout(timeoutRef.current);
2159
2278
  };
2160
2279
  }, []);
2161
- return React.useMemo(() => {
2162
- if (!enabled) {
2163
- return {};
2164
- }
2165
- return {
2166
- reference: {
2167
- onPointerDown(event) {
2168
- if (isVirtualPointerEvent(event.nativeEvent)) return;
2169
- keyboardModalityRef.current = false;
2170
- },
2171
- onMouseLeave() {
2172
- blockFocusRef.current = false;
2173
- },
2174
- onFocus(event) {
2175
- if (blockFocusRef.current) return;
2176
- const target = getTarget(event.nativeEvent);
2177
- if (visibleOnly && isElement(target)) {
2178
- try {
2179
- // Mac Safari unreliably matches `:focus-visible` on the reference
2180
- // if focus was outside the page initially - use the fallback
2181
- // instead.
2182
- if (isSafari() && isMac()) throw Error();
2183
- if (!target.matches(':focus-visible')) return;
2184
- } catch (e) {
2185
- // Old browsers will throw an error when using `:focus-visible`.
2186
- if (!keyboardModalityRef.current && !isTypeableElement(target)) {
2187
- return;
2188
- }
2189
- }
2280
+ const reference = React.useMemo(() => ({
2281
+ onPointerDown(event) {
2282
+ if (isVirtualPointerEvent(event.nativeEvent)) return;
2283
+ keyboardModalityRef.current = false;
2284
+ },
2285
+ onMouseLeave() {
2286
+ blockFocusRef.current = false;
2287
+ },
2288
+ onFocus(event) {
2289
+ if (blockFocusRef.current) return;
2290
+ const target = getTarget(event.nativeEvent);
2291
+ if (visibleOnly && isElement(target)) {
2292
+ try {
2293
+ // Mac Safari unreliably matches `:focus-visible` on the reference
2294
+ // if focus was outside the page initially - use the fallback
2295
+ // instead.
2296
+ if (isSafari() && isMac()) throw Error();
2297
+ if (!target.matches(':focus-visible')) return;
2298
+ } catch (e) {
2299
+ // Old browsers will throw an error when using `:focus-visible`.
2300
+ if (!keyboardModalityRef.current && !isTypeableElement(target)) {
2301
+ return;
2190
2302
  }
2191
- onOpenChange(true, event.nativeEvent, 'focus');
2192
- },
2193
- onBlur(event) {
2194
- blockFocusRef.current = false;
2195
- const relatedTarget = event.relatedTarget;
2196
-
2197
- // Hit the non-modal focus management portal guard. Focus will be
2198
- // moved into the floating element immediately after.
2199
- const movedToFocusGuard = isElement(relatedTarget) && relatedTarget.hasAttribute(createAttribute('focus-guard')) && relatedTarget.getAttribute('data-type') === 'outside';
2200
-
2201
- // Wait for the window blur listener to fire.
2202
- timeoutRef.current = window.setTimeout(() => {
2203
- const activeEl = activeElement(domReference ? domReference.ownerDocument : document);
2204
-
2205
- // Focus left the page, keep it open.
2206
- if (!relatedTarget && activeEl === domReference) return;
2207
-
2208
- // When focusing the reference element (e.g. regular click), then
2209
- // clicking into the floating element, prevent it from hiding.
2210
- // Note: it must be focusable, e.g. `tabindex="-1"`.
2211
- // We can not rely on relatedTarget to point to the correct element
2212
- // as it will only point to the shadow host of the newly focused element
2213
- // and not the element that actually has received focus if it is located
2214
- // inside a shadow root.
2215
- if (contains(refs.floating.current, activeEl) || contains(domReference, activeEl) || movedToFocusGuard) {
2216
- return;
2217
- }
2218
- onOpenChange(false, event.nativeEvent, 'focus');
2219
- });
2220
2303
  }
2221
2304
  }
2222
- };
2223
- }, [enabled, visibleOnly, domReference, refs, onOpenChange]);
2305
+ onOpenChange(true, event.nativeEvent, 'focus');
2306
+ },
2307
+ onBlur(event) {
2308
+ blockFocusRef.current = false;
2309
+ const relatedTarget = event.relatedTarget;
2310
+ const nativeEvent = event.nativeEvent;
2311
+
2312
+ // Hit the non-modal focus management portal guard. Focus will be
2313
+ // moved into the floating element immediately after.
2314
+ const movedToFocusGuard = isElement(relatedTarget) && relatedTarget.hasAttribute(createAttribute('focus-guard')) && relatedTarget.getAttribute('data-type') === 'outside';
2315
+
2316
+ // Wait for the window blur listener to fire.
2317
+ timeoutRef.current = window.setTimeout(() => {
2318
+ var _dataRef$current$floa;
2319
+ const activeEl = activeElement(elements.domReference ? elements.domReference.ownerDocument : document);
2320
+
2321
+ // Focus left the page, keep it open.
2322
+ if (!relatedTarget && activeEl === elements.domReference) return;
2323
+
2324
+ // When focusing the reference element (e.g. regular click), then
2325
+ // clicking into the floating element, prevent it from hiding.
2326
+ // Note: it must be focusable, e.g. `tabindex="-1"`.
2327
+ // We can not rely on relatedTarget to point to the correct element
2328
+ // as it will only point to the shadow host of the newly focused element
2329
+ // and not the element that actually has received focus if it is located
2330
+ // inside a shadow root.
2331
+ if (contains((_dataRef$current$floa = dataRef.current.floatingContext) == null ? void 0 : _dataRef$current$floa.refs.floating.current, activeEl) || contains(elements.domReference, activeEl) || movedToFocusGuard) {
2332
+ return;
2333
+ }
2334
+ onOpenChange(false, nativeEvent, 'focus');
2335
+ });
2336
+ }
2337
+ }), [dataRef, elements.domReference, onOpenChange, visibleOnly]);
2338
+ return React.useMemo(() => enabled ? {
2339
+ reference
2340
+ } : {}, [enabled, reference]);
2224
2341
  }
2225
2342
 
2226
2343
  const ACTIVE_KEY = 'active';
@@ -2280,7 +2397,6 @@ function mergeProps(userProps, propsList, elementKey) {
2280
2397
  }, {})
2281
2398
  };
2282
2399
  }
2283
-
2284
2400
  /**
2285
2401
  * Merges an array of interaction hooks' props into prop getters, allowing
2286
2402
  * event handler functions to be composed together without overwriting one
@@ -2291,22 +2407,18 @@ function useInteractions(propsList) {
2291
2407
  if (propsList === void 0) {
2292
2408
  propsList = [];
2293
2409
  }
2294
- // The dependencies are a dynamic array, so we can't use the linter's
2295
- // suggestion to add it to the deps array.
2296
- const deps = propsList;
2410
+ const referenceDeps = propsList.map(key => key == null ? void 0 : key.reference);
2411
+ const floatingDeps = propsList.map(key => key == null ? void 0 : key.floating);
2412
+ const itemDeps = propsList.map(key => key == null ? void 0 : key.item);
2297
2413
  const getReferenceProps = React.useCallback(userProps => mergeProps(userProps, propsList, 'reference'),
2298
2414
  // eslint-disable-next-line react-hooks/exhaustive-deps
2299
- deps);
2415
+ referenceDeps);
2300
2416
  const getFloatingProps = React.useCallback(userProps => mergeProps(userProps, propsList, 'floating'),
2301
2417
  // eslint-disable-next-line react-hooks/exhaustive-deps
2302
- deps);
2418
+ floatingDeps);
2303
2419
  const getItemProps = React.useCallback(userProps => mergeProps(userProps, propsList, 'item'),
2304
- // Granularly check for `item` changes, because the `getItemProps` getter
2305
- // should be as referentially stable as possible since it may be passed as
2306
- // a prop to many components. All `item` key values must therefore be
2307
- // memoized.
2308
2420
  // eslint-disable-next-line react-hooks/exhaustive-deps
2309
- propsList.map(key => key == null ? void 0 : key.item));
2421
+ itemDeps);
2310
2422
  return React.useMemo(() => ({
2311
2423
  getReferenceProps,
2312
2424
  getFloatingProps,
@@ -2354,11 +2466,7 @@ function useListNavigation(context, props) {
2354
2466
  const {
2355
2467
  open,
2356
2468
  onOpenChange,
2357
- refs,
2358
- elements: {
2359
- domReference,
2360
- floating
2361
- }
2469
+ elements
2362
2470
  } = context;
2363
2471
  const {
2364
2472
  listRef,
@@ -2403,47 +2511,59 @@ function useListNavigation(context, props) {
2403
2511
  const keyRef = React.useRef(null);
2404
2512
  const isPointerModalityRef = React.useRef(true);
2405
2513
  const previousOnNavigateRef = React.useRef(onNavigate);
2406
- const previousMountedRef = React.useRef(!!floating);
2514
+ const previousMountedRef = React.useRef(!!elements.floating);
2515
+ const previousOpenRef = React.useRef(open);
2407
2516
  const forceSyncFocus = React.useRef(false);
2408
2517
  const forceScrollIntoViewRef = React.useRef(false);
2409
2518
  const disabledIndicesRef = useLatestRef(disabledIndices);
2410
2519
  const latestOpenRef = useLatestRef(open);
2411
2520
  const scrollItemIntoViewRef = useLatestRef(scrollItemIntoView);
2521
+ const floatingRef = useLatestRef(elements.floating);
2522
+ const selectedIndexRef = useLatestRef(selectedIndex);
2412
2523
  const [activeId, setActiveId] = React.useState();
2413
2524
  const [virtualId, setVirtualId] = React.useState();
2414
2525
  const focusItem = useEffectEvent(function (listRef, indexRef, forceScrollIntoView) {
2415
2526
  if (forceScrollIntoView === void 0) {
2416
2527
  forceScrollIntoView = false;
2417
2528
  }
2418
- const item = listRef.current[indexRef.current];
2419
- if (!item) return;
2420
- if (virtual) {
2421
- setActiveId(item.id);
2422
- tree == null || tree.events.emit('virtualfocus', item);
2423
- if (virtualItemRef) {
2424
- virtualItemRef.current = item;
2529
+ function runFocus(item) {
2530
+ if (virtual) {
2531
+ setActiveId(item.id);
2532
+ tree == null || tree.events.emit('virtualfocus', item);
2533
+ if (virtualItemRef) {
2534
+ virtualItemRef.current = item;
2535
+ }
2536
+ } else {
2537
+ enqueueFocus(item, {
2538
+ preventScroll: true,
2539
+ // Mac Safari does not move the virtual cursor unless the focus call
2540
+ // is sync. However, for the very first focus call, we need to wait
2541
+ // for the position to be ready in order to prevent unwanted
2542
+ // scrolling. This means the virtual cursor will not move to the first
2543
+ // item when first opening the floating element, but will on
2544
+ // subsequent calls. `preventScroll` is supported in modern Safari,
2545
+ // so we can use that instead.
2546
+ // iOS Safari must be async or the first item will not be focused.
2547
+ sync: isMac() && isSafari() ? isPreventScrollSupported || forceSyncFocus.current : false
2548
+ });
2425
2549
  }
2426
- } else {
2427
- enqueueFocus(item, {
2428
- preventScroll: true,
2429
- // Mac Safari does not move the virtual cursor unless the focus call
2430
- // is sync. However, for the very first focus call, we need to wait
2431
- // for the position to be ready in order to prevent unwanted
2432
- // scrolling. This means the virtual cursor will not move to the first
2433
- // item when first opening the floating element, but will on
2434
- // subsequent calls. `preventScroll` is supported in modern Safari,
2435
- // so we can use that instead.
2436
- // iOS Safari must be async or the first item will not be focused.
2437
- sync: isMac() && isSafari() ? isPreventScrollSupported || forceSyncFocus.current : false
2438
- });
2550
+ }
2551
+ const initialItem = listRef.current[indexRef.current];
2552
+ if (initialItem) {
2553
+ runFocus(initialItem);
2439
2554
  }
2440
2555
  requestAnimationFrame(() => {
2556
+ const waitedItem = listRef.current[indexRef.current] || initialItem;
2557
+ if (!waitedItem) return;
2558
+ if (!initialItem) {
2559
+ runFocus(waitedItem);
2560
+ }
2441
2561
  const scrollIntoViewOptions = scrollItemIntoViewRef.current;
2442
2562
  const shouldScrollIntoView = scrollIntoViewOptions && item && (forceScrollIntoView || !isPointerModalityRef.current);
2443
2563
  if (shouldScrollIntoView) {
2444
2564
  // JSDOM doesn't support `.scrollIntoView()` but it's widely supported
2445
2565
  // by all browsers.
2446
- item.scrollIntoView == null || item.scrollIntoView(typeof scrollIntoViewOptions === 'boolean' ? {
2566
+ waitedItem.scrollIntoView == null || waitedItem.scrollIntoView(typeof scrollIntoViewOptions === 'boolean' ? {
2447
2567
  block: 'nearest',
2448
2568
  inline: 'nearest'
2449
2569
  } : scrollIntoViewOptions);
@@ -2462,10 +2582,8 @@ function useListNavigation(context, props) {
2462
2582
  // Sync `selectedIndex` to be the `activeIndex` upon opening the floating
2463
2583
  // element. Also, reset `activeIndex` upon closing the floating element.
2464
2584
  index(() => {
2465
- if (!enabled) {
2466
- return;
2467
- }
2468
- if (open && floating) {
2585
+ if (!enabled) return;
2586
+ if (open && elements.floating) {
2469
2587
  if (focusItemOnOpenRef.current && selectedIndex != null) {
2470
2588
  // Regardless of the pointer modality, we want to ensure the selected
2471
2589
  // item comes into view when the floating element is opened.
@@ -2480,18 +2598,16 @@ function useListNavigation(context, props) {
2480
2598
  indexRef.current = -1;
2481
2599
  previousOnNavigateRef.current(null);
2482
2600
  }
2483
- }, [enabled, open, floating, selectedIndex, onNavigate]);
2601
+ }, [enabled, open, elements.floating, selectedIndex, onNavigate]);
2484
2602
 
2485
2603
  // Sync `activeIndex` to be the focused item while the floating element is
2486
2604
  // open.
2487
2605
  index(() => {
2488
- if (!enabled) {
2489
- return;
2490
- }
2491
- if (open && floating) {
2606
+ if (!enabled) return;
2607
+ if (open && elements.floating) {
2492
2608
  if (activeIndex == null) {
2493
2609
  forceSyncFocus.current = false;
2494
- if (selectedIndex != null) {
2610
+ if (selectedIndexRef.current != null) {
2495
2611
  return;
2496
2612
  }
2497
2613
 
@@ -2502,7 +2618,7 @@ function useListNavigation(context, props) {
2502
2618
  }
2503
2619
 
2504
2620
  // Initial sync.
2505
- if (!previousMountedRef.current && focusItemOnOpenRef.current && (keyRef.current != null || focusItemOnOpenRef.current === true && keyRef.current == null)) {
2621
+ if ((!previousOpenRef.current || !previousMountedRef.current) && focusItemOnOpenRef.current && (keyRef.current != null || focusItemOnOpenRef.current === true && keyRef.current == null)) {
2506
2622
  let runs = 0;
2507
2623
  const waitForListPopulated = () => {
2508
2624
  if (listRef.current[0] == null) {
@@ -2528,27 +2644,30 @@ function useListNavigation(context, props) {
2528
2644
  forceScrollIntoViewRef.current = false;
2529
2645
  }
2530
2646
  }
2531
- }, [enabled, open, floating, activeIndex, selectedIndex, nested, listRef, orientation, rtl, onNavigate, focusItem, disabledIndicesRef]);
2647
+ }, [enabled, open, elements.floating, activeIndex, selectedIndexRef, nested, listRef, orientation, rtl, onNavigate, focusItem, disabledIndicesRef]);
2532
2648
 
2533
2649
  // Ensure the parent floating element has focus when a nested child closes
2534
2650
  // to allow arrow key navigation to work after the pointer leaves the child.
2535
2651
  index(() => {
2536
2652
  var _nodes$find;
2537
- if (!enabled || floating || !tree || virtual || !previousMountedRef.current) {
2653
+ if (!enabled || elements.floating || !tree || virtual || !previousMountedRef.current) {
2538
2654
  return;
2539
2655
  }
2540
2656
  const nodes = tree.nodesRef.current;
2541
2657
  const parent = (_nodes$find = nodes.find(node => node.id === parentId)) == null || (_nodes$find = _nodes$find.context) == null ? void 0 : _nodes$find.elements.floating;
2542
- const activeEl = activeElement(getDocument(floating));
2658
+ const activeEl = activeElement(getDocument(elements.floating));
2543
2659
  const treeContainsActiveEl = nodes.some(node => node.context && contains(node.context.elements.floating, activeEl));
2544
2660
  if (parent && !treeContainsActiveEl && isPointerModalityRef.current) {
2545
2661
  parent.focus({
2546
2662
  preventScroll: true
2547
2663
  });
2548
2664
  }
2549
- }, [enabled, floating, tree, parentId, virtual]);
2665
+ }, [enabled, elements.floating, tree, parentId, virtual]);
2550
2666
  index(() => {
2551
- if (!enabled || !tree || !virtual || parentId) return;
2667
+ if (!enabled) return;
2668
+ if (!tree) return;
2669
+ if (!virtual) return;
2670
+ if (parentId) return;
2552
2671
  function handleVirtualFocus(item) {
2553
2672
  setVirtualId(item.id);
2554
2673
  if (virtualItemRef) {
@@ -2562,13 +2681,16 @@ function useListNavigation(context, props) {
2562
2681
  }, [enabled, tree, virtual, parentId, virtualItemRef]);
2563
2682
  index(() => {
2564
2683
  previousOnNavigateRef.current = onNavigate;
2565
- previousMountedRef.current = !!floating;
2684
+ previousMountedRef.current = !!elements.floating;
2566
2685
  });
2567
2686
  index(() => {
2568
2687
  if (!open) {
2569
2688
  keyRef.current = null;
2570
2689
  }
2571
2690
  }, [open]);
2691
+ index(() => {
2692
+ previousOpenRef.current = open;
2693
+ }, [open]);
2572
2694
  const hasActiveIndex = activeIndex != null;
2573
2695
  const item = React.useMemo(() => {
2574
2696
  function syncCurrentTarget(currentTarget) {
@@ -2612,7 +2734,7 @@ function useListNavigation(context, props) {
2612
2734
  focusItem(listRef, indexRef);
2613
2735
  onNavigate(null);
2614
2736
  if (!virtual) {
2615
- enqueueFocus(refs.floating.current, {
2737
+ enqueueFocus(floatingRef.current, {
2616
2738
  preventScroll: true
2617
2739
  });
2618
2740
  }
@@ -2620,126 +2742,137 @@ function useListNavigation(context, props) {
2620
2742
  })
2621
2743
  };
2622
2744
  return props;
2623
- }, [open, refs, focusItem, focusItemOnHover, listRef, onNavigate, virtual]);
2624
- return React.useMemo(() => {
2625
- if (!enabled) {
2626
- return {};
2745
+ }, [open, floatingRef, focusItem, focusItemOnHover, listRef, onNavigate, virtual]);
2746
+ const commonOnKeyDown = useEffectEvent(event => {
2747
+ isPointerModalityRef.current = false;
2748
+ forceSyncFocus.current = true;
2749
+
2750
+ // If the floating element is animating out, ignore navigation. Otherwise,
2751
+ // the `activeIndex` gets set to 0 despite not being open so the next time
2752
+ // the user ArrowDowns, the first item won't be focused.
2753
+ if (!latestOpenRef.current && event.currentTarget === floatingRef.current) {
2754
+ return;
2627
2755
  }
2628
- const disabledIndices = disabledIndicesRef.current;
2629
- function onKeyDown(event) {
2630
- isPointerModalityRef.current = false;
2631
- forceSyncFocus.current = true;
2632
-
2633
- // If the floating element is animating out, ignore navigation. Otherwise,
2634
- // the `activeIndex` gets set to 0 despite not being open so the next time
2635
- // the user ArrowDowns, the first item won't be focused.
2636
- if (!latestOpenRef.current && event.currentTarget === refs.floating.current) {
2637
- return;
2756
+ if (nested && isCrossOrientationCloseKey(event.key, orientation, rtl)) {
2757
+ stopEvent(event);
2758
+ onOpenChange(false, event.nativeEvent, 'list-navigation');
2759
+ if (isHTMLElement(elements.domReference) && !virtual) {
2760
+ elements.domReference.focus();
2638
2761
  }
2639
- if (nested && isCrossOrientationCloseKey(event.key, orientation, rtl)) {
2640
- stopEvent(event);
2641
- onOpenChange(false, event.nativeEvent, 'list-navigation');
2642
- if (isHTMLElement(domReference) && !virtual) {
2643
- domReference.focus();
2644
- }
2762
+ return;
2763
+ }
2764
+ const currentIndex = indexRef.current;
2765
+ const minIndex = getMinIndex(listRef, disabledIndices);
2766
+ const maxIndex = getMaxIndex(listRef, disabledIndices);
2767
+ if (event.key === 'Home') {
2768
+ stopEvent(event);
2769
+ indexRef.current = minIndex;
2770
+ onNavigate(indexRef.current);
2771
+ }
2772
+ if (event.key === 'End') {
2773
+ stopEvent(event);
2774
+ indexRef.current = maxIndex;
2775
+ onNavigate(indexRef.current);
2776
+ }
2777
+
2778
+ // Grid navigation.
2779
+ if (cols > 1) {
2780
+ const sizes = itemSizes || Array.from({
2781
+ length: listRef.current.length
2782
+ }, () => ({
2783
+ width: 1,
2784
+ height: 1
2785
+ }));
2786
+ // To calculate movements on the grid, we use hypothetical cell indices
2787
+ // as if every item was 1x1, then convert back to real indices.
2788
+ const cellMap = buildCellMap(sizes, cols, dense);
2789
+ const minGridIndex = cellMap.findIndex(index => index != null && !isDisabled(listRef.current, index, disabledIndices));
2790
+ // last enabled index
2791
+ const maxGridIndex = cellMap.reduce((foundIndex, index, cellIndex) => index != null && !isDisabled(listRef.current, index, disabledIndices) ? cellIndex : foundIndex, -1);
2792
+ indexRef.current = cellMap[getGridNavigatedIndex({
2793
+ current: cellMap.map(itemIndex => itemIndex != null ? listRef.current[itemIndex] : null)
2794
+ }, {
2795
+ event,
2796
+ orientation,
2797
+ loop,
2798
+ cols,
2799
+ // treat undefined (empty grid spaces) as disabled indices so we
2800
+ // don't end up in them
2801
+ disabledIndices: getCellIndices([...(disabledIndices || listRef.current.map((_, index) => isDisabled(listRef.current, index) ? index : undefined)), undefined], cellMap),
2802
+ minIndex: minGridIndex,
2803
+ maxIndex: maxGridIndex,
2804
+ prevIndex: getCellIndexOfCorner(indexRef.current > maxIndex ? minIndex : indexRef.current, sizes, cellMap, cols,
2805
+ // use a corner matching the edge closest to the direction
2806
+ // we're moving in so we don't end up in the same item. Prefer
2807
+ // top/left over bottom/right.
2808
+ event.key === ARROW_DOWN ? 'bl' : event.key === ARROW_RIGHT ? 'tr' : 'tl'),
2809
+ stopEvent: true
2810
+ })]; // navigated cell will never be nullish
2811
+
2812
+ onNavigate(indexRef.current);
2813
+ if (orientation === 'both') {
2645
2814
  return;
2646
2815
  }
2647
- const currentIndex = indexRef.current;
2648
- const minIndex = getMinIndex(listRef, disabledIndices);
2649
- const maxIndex = getMaxIndex(listRef, disabledIndices);
2650
- if (event.key === 'Home') {
2651
- stopEvent(event);
2652
- indexRef.current = minIndex;
2653
- onNavigate(indexRef.current);
2654
- }
2655
- if (event.key === 'End') {
2656
- stopEvent(event);
2657
- indexRef.current = maxIndex;
2658
- onNavigate(indexRef.current);
2659
- }
2660
-
2661
- // Grid navigation.
2662
- if (cols > 1) {
2663
- const sizes = itemSizes || Array.from({
2664
- length: listRef.current.length
2665
- }, () => ({
2666
- width: 1,
2667
- height: 1
2668
- }));
2669
- // To calculate movements on the grid, we use hypothetical cell indices
2670
- // as if every item was 1x1, then convert back to real indices.
2671
- const cellMap = buildCellMap(sizes, cols, dense);
2672
- const minGridIndex = cellMap.findIndex(index => index != null && !(disabledIndices != null && disabledIndices.includes(index)));
2673
- // last enabled index
2674
- const maxGridIndex = cellMap.reduce((foundIndex, index, cellIndex) => index != null && !(disabledIndices != null && disabledIndices.includes(index)) ? cellIndex : foundIndex, -1);
2675
- indexRef.current = cellMap[getGridNavigatedIndex({
2676
- current: cellMap.map(itemIndex => itemIndex != null ? listRef.current[itemIndex] : null)
2677
- }, {
2678
- event,
2679
- orientation,
2680
- loop,
2681
- cols,
2682
- // treat undefined (empty grid spaces) as disabled indices so we
2683
- // don't end up in them
2684
- disabledIndices: getCellIndices([...(disabledIndices || []), undefined], cellMap),
2685
- minIndex: minGridIndex,
2686
- maxIndex: maxGridIndex,
2687
- prevIndex: getCellIndexOfCorner(indexRef.current, sizes, cellMap, cols,
2688
- // use a corner matching the edge closest to the direction
2689
- // we're moving in so we don't end up in the same item. Prefer
2690
- // top/left over bottom/right.
2691
- event.key === ARROW_DOWN ? 'bl' : event.key === ARROW_RIGHT ? 'tr' : 'tl'),
2692
- stopEvent: true
2693
- })]; // navigated cell will never be nullish
2816
+ }
2817
+ if (isMainOrientationKey(event.key, orientation)) {
2818
+ stopEvent(event);
2694
2819
 
2820
+ // Reset the index if no item is focused.
2821
+ if (open && !virtual && activeElement(event.currentTarget.ownerDocument) === event.currentTarget) {
2822
+ indexRef.current = isMainOrientationToEndKey(event.key, orientation, rtl) ? minIndex : maxIndex;
2695
2823
  onNavigate(indexRef.current);
2696
- if (orientation === 'both') {
2697
- return;
2698
- }
2824
+ return;
2699
2825
  }
2700
- if (isMainOrientationKey(event.key, orientation)) {
2701
- stopEvent(event);
2702
-
2703
- // Reset the index if no item is focused.
2704
- if (open && !virtual && activeElement(event.currentTarget.ownerDocument) === event.currentTarget) {
2705
- indexRef.current = isMainOrientationToEndKey(event.key, orientation, rtl) ? minIndex : maxIndex;
2706
- onNavigate(indexRef.current);
2707
- return;
2708
- }
2709
- if (isMainOrientationToEndKey(event.key, orientation, rtl)) {
2710
- if (loop) {
2711
- indexRef.current = currentIndex >= maxIndex ? allowEscape && currentIndex !== listRef.current.length ? -1 : minIndex : findNonDisabledIndex(listRef, {
2712
- startingIndex: currentIndex,
2713
- disabledIndices
2714
- });
2715
- } else {
2716
- indexRef.current = Math.min(maxIndex, findNonDisabledIndex(listRef, {
2717
- startingIndex: currentIndex,
2718
- disabledIndices
2719
- }));
2720
- }
2826
+ if (isMainOrientationToEndKey(event.key, orientation, rtl)) {
2827
+ if (loop) {
2828
+ indexRef.current = currentIndex >= maxIndex ? allowEscape && currentIndex !== listRef.current.length ? -1 : minIndex : findNonDisabledIndex(listRef, {
2829
+ startingIndex: currentIndex,
2830
+ disabledIndices
2831
+ });
2721
2832
  } else {
2722
- if (loop) {
2723
- indexRef.current = currentIndex <= minIndex ? allowEscape && currentIndex !== -1 ? listRef.current.length : maxIndex : findNonDisabledIndex(listRef, {
2724
- startingIndex: currentIndex,
2725
- decrement: true,
2726
- disabledIndices
2727
- });
2728
- } else {
2729
- indexRef.current = Math.max(minIndex, findNonDisabledIndex(listRef, {
2730
- startingIndex: currentIndex,
2731
- decrement: true,
2732
- disabledIndices
2733
- }));
2734
- }
2833
+ indexRef.current = Math.min(maxIndex, findNonDisabledIndex(listRef, {
2834
+ startingIndex: currentIndex,
2835
+ disabledIndices
2836
+ }));
2735
2837
  }
2736
- if (isIndexOutOfBounds(listRef, indexRef.current)) {
2737
- onNavigate(null);
2838
+ } else {
2839
+ if (loop) {
2840
+ indexRef.current = currentIndex <= minIndex ? allowEscape && currentIndex !== -1 ? listRef.current.length : maxIndex : findNonDisabledIndex(listRef, {
2841
+ startingIndex: currentIndex,
2842
+ decrement: true,
2843
+ disabledIndices
2844
+ });
2738
2845
  } else {
2739
- onNavigate(indexRef.current);
2846
+ indexRef.current = Math.max(minIndex, findNonDisabledIndex(listRef, {
2847
+ startingIndex: currentIndex,
2848
+ decrement: true,
2849
+ disabledIndices
2850
+ }));
2740
2851
  }
2741
2852
  }
2853
+ if (isIndexOutOfBounds(listRef, indexRef.current)) {
2854
+ onNavigate(null);
2855
+ } else {
2856
+ onNavigate(indexRef.current);
2857
+ }
2742
2858
  }
2859
+ });
2860
+ const ariaActiveDescendantProp = React.useMemo(() => {
2861
+ return virtual && open && hasActiveIndex && {
2862
+ 'aria-activedescendant': virtualId || activeId
2863
+ };
2864
+ }, [virtual, open, hasActiveIndex, virtualId, activeId]);
2865
+ const floating = React.useMemo(() => {
2866
+ return {
2867
+ 'aria-orientation': orientation === 'both' ? undefined : orientation,
2868
+ ...(!isTypeableCombobox(elements.domReference) && ariaActiveDescendantProp),
2869
+ onKeyDown: commonOnKeyDown,
2870
+ onPointerMove() {
2871
+ isPointerModalityRef.current = true;
2872
+ }
2873
+ };
2874
+ }, [ariaActiveDescendantProp, commonOnKeyDown, elements.domReference, orientation]);
2875
+ const reference = React.useMemo(() => {
2743
2876
  function checkVirtualMouse(event) {
2744
2877
  if (focusItemOnOpen === 'auto' && isVirtualClick(event.nativeEvent)) {
2745
2878
  focusItemOnOpenRef.current = true;
@@ -2752,105 +2885,95 @@ function useListNavigation(context, props) {
2752
2885
  focusItemOnOpenRef.current = true;
2753
2886
  }
2754
2887
  }
2755
- const ariaActiveDescendantProp = virtual && open && hasActiveIndex && {
2756
- 'aria-activedescendant': virtualId || activeId
2757
- };
2758
- const activeItem = listRef.current.find(item => (item == null ? void 0 : item.id) === activeId);
2759
2888
  return {
2760
- reference: {
2761
- ...ariaActiveDescendantProp,
2762
- onKeyDown(event) {
2763
- isPointerModalityRef.current = false;
2764
- const isArrowKey = event.key.indexOf('Arrow') === 0;
2765
- const isCrossOpenKey = isCrossOrientationOpenKey(event.key, orientation, rtl);
2766
- const isCrossCloseKey = isCrossOrientationCloseKey(event.key, orientation, rtl);
2767
- const isMainKey = isMainOrientationKey(event.key, orientation);
2768
- const isNavigationKey = (nested ? isCrossOpenKey : isMainKey) || event.key === 'Enter' || event.key.trim() === '';
2769
- if (virtual && open) {
2770
- const rootNode = tree == null ? void 0 : tree.nodesRef.current.find(node => node.parentId == null);
2771
- const deepestNode = tree && rootNode ? getDeepestNode(tree.nodesRef.current, rootNode.id) : null;
2772
- if (isArrowKey && deepestNode && virtualItemRef) {
2773
- const eventObject = new KeyboardEvent('keydown', {
2774
- key: event.key,
2775
- bubbles: true
2776
- });
2777
- if (isCrossOpenKey || isCrossCloseKey) {
2778
- var _deepestNode$context, _deepestNode$context2;
2779
- const isCurrentTarget = ((_deepestNode$context = deepestNode.context) == null ? void 0 : _deepestNode$context.elements.domReference) === event.currentTarget;
2780
- const dispatchItem = isCrossCloseKey && !isCurrentTarget ? (_deepestNode$context2 = deepestNode.context) == null ? void 0 : _deepestNode$context2.elements.domReference : isCrossOpenKey ? activeItem : null;
2781
- if (dispatchItem) {
2782
- stopEvent(event);
2783
- dispatchItem.dispatchEvent(eventObject);
2784
- setVirtualId(undefined);
2785
- }
2786
- }
2787
- if (isMainKey && deepestNode.context) {
2788
- if (deepestNode.context.open && deepestNode.parentId && event.currentTarget !== deepestNode.context.elements.domReference) {
2789
- var _deepestNode$context$;
2790
- stopEvent(event);
2791
- (_deepestNode$context$ = deepestNode.context.elements.domReference) == null || _deepestNode$context$.dispatchEvent(eventObject);
2792
- return;
2793
- }
2889
+ ...ariaActiveDescendantProp,
2890
+ onKeyDown(event) {
2891
+ isPointerModalityRef.current = false;
2892
+ const isArrowKey = event.key.indexOf('Arrow') === 0;
2893
+ const isCrossOpenKey = isCrossOrientationOpenKey(event.key, orientation, rtl);
2894
+ const isCrossCloseKey = isCrossOrientationCloseKey(event.key, orientation, rtl);
2895
+ const isMainKey = isMainOrientationKey(event.key, orientation);
2896
+ const isNavigationKey = (nested ? isCrossOpenKey : isMainKey) || event.key === 'Enter' || event.key.trim() === '';
2897
+ if (virtual && open) {
2898
+ const rootNode = tree == null ? void 0 : tree.nodesRef.current.find(node => node.parentId == null);
2899
+ const deepestNode = tree && rootNode ? getDeepestNode(tree.nodesRef.current, rootNode.id) : null;
2900
+ if (isArrowKey && deepestNode && virtualItemRef) {
2901
+ const eventObject = new KeyboardEvent('keydown', {
2902
+ key: event.key,
2903
+ bubbles: true
2904
+ });
2905
+ if (isCrossOpenKey || isCrossCloseKey) {
2906
+ var _deepestNode$context, _deepestNode$context2;
2907
+ const isCurrentTarget = ((_deepestNode$context = deepestNode.context) == null ? void 0 : _deepestNode$context.elements.domReference) === event.currentTarget;
2908
+ const dispatchItem = isCrossCloseKey && !isCurrentTarget ? (_deepestNode$context2 = deepestNode.context) == null ? void 0 : _deepestNode$context2.elements.domReference : isCrossOpenKey ? listRef.current.find(item => (item == null ? void 0 : item.id) === activeId) : null;
2909
+ if (dispatchItem) {
2910
+ stopEvent(event);
2911
+ dispatchItem.dispatchEvent(eventObject);
2912
+ setVirtualId(undefined);
2794
2913
  }
2795
2914
  }
2796
- return onKeyDown(event);
2797
- }
2798
-
2799
- // If a floating element should not open on arrow key down, avoid
2800
- // setting `activeIndex` while it's closed.
2801
- if (!open && !openOnArrowKeyDown && isArrowKey) {
2802
- return;
2803
- }
2804
- if (isNavigationKey) {
2805
- keyRef.current = nested && isMainKey ? null : event.key;
2806
- }
2807
- if (nested) {
2808
- if (isCrossOpenKey) {
2809
- stopEvent(event);
2810
- if (open) {
2811
- indexRef.current = getMinIndex(listRef, disabledIndices);
2812
- onNavigate(indexRef.current);
2813
- } else {
2814
- onOpenChange(true, event.nativeEvent, 'list-navigation');
2915
+ if (isMainKey && deepestNode.context) {
2916
+ if (deepestNode.context.open && deepestNode.parentId && event.currentTarget !== deepestNode.context.elements.domReference) {
2917
+ var _deepestNode$context$;
2918
+ stopEvent(event);
2919
+ (_deepestNode$context$ = deepestNode.context.elements.domReference) == null || _deepestNode$context$.dispatchEvent(eventObject);
2920
+ return;
2815
2921
  }
2816
2922
  }
2817
- return;
2818
2923
  }
2819
- if (isMainKey) {
2820
- if (selectedIndex != null) {
2821
- indexRef.current = selectedIndex;
2822
- }
2924
+ return commonOnKeyDown(event);
2925
+ }
2926
+
2927
+ // If a floating element should not open on arrow key down, avoid
2928
+ // setting `activeIndex` while it's closed.
2929
+ if (!open && !openOnArrowKeyDown && isArrowKey) {
2930
+ return;
2931
+ }
2932
+ if (isNavigationKey) {
2933
+ keyRef.current = nested && isMainKey ? null : event.key;
2934
+ }
2935
+ if (nested) {
2936
+ if (isCrossOpenKey) {
2823
2937
  stopEvent(event);
2824
- if (!open && openOnArrowKeyDown) {
2825
- onOpenChange(true, event.nativeEvent, 'list-navigation');
2826
- } else {
2827
- onKeyDown(event);
2828
- }
2829
2938
  if (open) {
2939
+ indexRef.current = getMinIndex(listRef, disabledIndicesRef.current);
2830
2940
  onNavigate(indexRef.current);
2941
+ } else {
2942
+ onOpenChange(true, event.nativeEvent, 'list-navigation');
2831
2943
  }
2832
2944
  }
2833
- },
2834
- onFocus() {
2945
+ return;
2946
+ }
2947
+ if (isMainKey) {
2948
+ if (selectedIndex != null) {
2949
+ indexRef.current = selectedIndex;
2950
+ }
2951
+ stopEvent(event);
2952
+ if (!open && openOnArrowKeyDown) {
2953
+ onOpenChange(true, event.nativeEvent, 'list-navigation');
2954
+ } else {
2955
+ commonOnKeyDown(event);
2956
+ }
2835
2957
  if (open) {
2836
- onNavigate(null);
2958
+ onNavigate(indexRef.current);
2837
2959
  }
2838
- },
2839
- onPointerDown: checkVirtualPointer,
2840
- onMouseDown: checkVirtualMouse,
2841
- onClick: checkVirtualMouse
2960
+ }
2842
2961
  },
2843
- floating: {
2844
- 'aria-orientation': orientation === 'both' ? undefined : orientation,
2845
- ...(!isTypeableCombobox(domReference) && ariaActiveDescendantProp),
2846
- onKeyDown,
2847
- onPointerMove() {
2848
- isPointerModalityRef.current = true;
2962
+ onFocus() {
2963
+ if (open && !virtual) {
2964
+ onNavigate(null);
2849
2965
  }
2850
2966
  },
2851
- item
2967
+ onPointerDown: checkVirtualPointer,
2968
+ onMouseDown: checkVirtualMouse,
2969
+ onClick: checkVirtualMouse
2852
2970
  };
2853
- }, [domReference, refs, activeId, virtualId, disabledIndicesRef, latestOpenRef, listRef, enabled, orientation, rtl, virtual, open, hasActiveIndex, nested, selectedIndex, openOnArrowKeyDown, allowEscape, cols, loop, focusItemOnOpen, onNavigate, onOpenChange, item, tree, virtualItemRef, itemSizes, dense]);
2971
+ }, [activeId, ariaActiveDescendantProp, commonOnKeyDown, disabledIndicesRef, focusItemOnOpen, listRef, nested, onNavigate, onOpenChange, open, openOnArrowKeyDown, orientation, rtl, selectedIndex, tree, virtual, virtualItemRef]);
2972
+ return React.useMemo(() => enabled ? {
2973
+ reference,
2974
+ floating,
2975
+ item
2976
+ } : {}, [enabled, reference, floating, item]);
2854
2977
  }
2855
2978
 
2856
2979
  const componentRoleToAriaRoleMap = /*#__PURE__*/new Map([['select', 'listbox'], ['combobox', 'listbox'], ['label', false]]);
@@ -2877,8 +3000,34 @@ function useRole(context, props) {
2877
3000
  const referenceId = useId();
2878
3001
  const parentId = useFloatingParentNodeId();
2879
3002
  const isNested = parentId != null;
2880
- return React.useMemo(() => {
2881
- if (!enabled) return {};
3003
+ const reference = React.useMemo(() => {
3004
+ if (ariaRole === 'tooltip' || role === 'label') {
3005
+ return {
3006
+ ["aria-" + (role === 'label' ? 'labelledby' : 'describedby')]: open ? floatingId : undefined
3007
+ };
3008
+ }
3009
+ return {
3010
+ 'aria-expanded': open ? 'true' : 'false',
3011
+ 'aria-haspopup': ariaRole === 'alertdialog' ? 'dialog' : ariaRole,
3012
+ 'aria-controls': open ? floatingId : undefined,
3013
+ ...(ariaRole === 'listbox' && {
3014
+ role: 'combobox'
3015
+ }),
3016
+ ...(ariaRole === 'menu' && {
3017
+ id: referenceId
3018
+ }),
3019
+ ...(ariaRole === 'menu' && isNested && {
3020
+ role: 'menuitem'
3021
+ }),
3022
+ ...(role === 'select' && {
3023
+ 'aria-autocomplete': 'none'
3024
+ }),
3025
+ ...(role === 'combobox' && {
3026
+ 'aria-autocomplete': 'list'
3027
+ })
3028
+ };
3029
+ }, [ariaRole, floatingId, isNested, open, referenceId, role]);
3030
+ const floating = React.useMemo(() => {
2882
3031
  const floatingProps = {
2883
3032
  id: floatingId,
2884
3033
  ...(ariaRole && {
@@ -2886,75 +3035,53 @@ function useRole(context, props) {
2886
3035
  })
2887
3036
  };
2888
3037
  if (ariaRole === 'tooltip' || role === 'label') {
2889
- return {
2890
- reference: {
2891
- ["aria-" + (role === 'label' ? 'labelledby' : 'describedby')]: open ? floatingId : undefined
2892
- },
2893
- floating: floatingProps
2894
- };
3038
+ return floatingProps;
2895
3039
  }
2896
3040
  return {
2897
- reference: {
2898
- 'aria-expanded': open ? 'true' : 'false',
2899
- 'aria-haspopup': ariaRole === 'alertdialog' ? 'dialog' : ariaRole,
2900
- 'aria-controls': open ? floatingId : undefined,
2901
- ...(ariaRole === 'listbox' && {
2902
- role: 'combobox'
2903
- }),
2904
- ...(ariaRole === 'menu' && {
2905
- id: referenceId
2906
- }),
2907
- ...(ariaRole === 'menu' && isNested && {
2908
- role: 'menuitem'
2909
- }),
2910
- ...(role === 'select' && {
2911
- 'aria-autocomplete': 'none'
2912
- }),
2913
- ...(role === 'combobox' && {
2914
- 'aria-autocomplete': 'list'
2915
- })
2916
- },
2917
- floating: {
2918
- ...floatingProps,
2919
- ...(ariaRole === 'menu' && {
2920
- 'aria-labelledby': referenceId
2921
- })
2922
- },
2923
- item(_ref) {
2924
- let {
2925
- active,
2926
- selected
2927
- } = _ref;
2928
- const commonProps = {
2929
- role: 'option',
2930
- ...(active && {
2931
- id: floatingId + "-option"
2932
- })
2933
- };
3041
+ ...floatingProps,
3042
+ ...(ariaRole === 'menu' && {
3043
+ 'aria-labelledby': referenceId
3044
+ })
3045
+ };
3046
+ }, [ariaRole, floatingId, referenceId, role]);
3047
+ const item = React.useCallback(_ref => {
3048
+ let {
3049
+ active,
3050
+ selected
3051
+ } = _ref;
3052
+ const commonProps = {
3053
+ role: 'option',
3054
+ ...(active && {
3055
+ id: floatingId + "-option"
3056
+ })
3057
+ };
2934
3058
 
2935
- // For `menu`, we are unable to tell if the item is a `menuitemradio`
2936
- // or `menuitemcheckbox`. For backwards-compatibility reasons, also
2937
- // avoid defaulting to `menuitem` as it may overwrite custom role props.
2938
- switch (role) {
2939
- case 'select':
2940
- return {
2941
- ...commonProps,
2942
- 'aria-selected': active && selected
2943
- };
2944
- case 'combobox':
2945
- {
2946
- return {
2947
- ...commonProps,
2948
- ...(active && {
2949
- 'aria-selected': true
2950
- })
2951
- };
2952
- }
3059
+ // For `menu`, we are unable to tell if the item is a `menuitemradio`
3060
+ // or `menuitemcheckbox`. For backwards-compatibility reasons, also
3061
+ // avoid defaulting to `menuitem` as it may overwrite custom role props.
3062
+ switch (role) {
3063
+ case 'select':
3064
+ return {
3065
+ ...commonProps,
3066
+ 'aria-selected': active && selected
3067
+ };
3068
+ case 'combobox':
3069
+ {
3070
+ return {
3071
+ ...commonProps,
3072
+ ...(active && {
3073
+ 'aria-selected': true
3074
+ })
3075
+ };
2953
3076
  }
2954
- return {};
2955
- }
2956
- };
2957
- }, [enabled, role, ariaRole, open, floatingId, referenceId, isNested]);
3077
+ }
3078
+ return {};
3079
+ }, [floatingId, role]);
3080
+ return React.useMemo(() => enabled ? {
3081
+ reference,
3082
+ floating,
3083
+ item
3084
+ } : {}, [enabled, reference, floating, item]);
2958
3085
  }
2959
3086
 
2960
3087
  // Converts a JS style key like `backgroundColor` to a CSS transition-property
@@ -2969,11 +3096,11 @@ function useDelayUnmount(open, durationMs) {
2969
3096
  setIsMounted(true);
2970
3097
  }
2971
3098
  React.useEffect(() => {
2972
- if (!open) {
3099
+ if (!open && isMounted) {
2973
3100
  const timeout = setTimeout(() => setIsMounted(false), durationMs);
2974
3101
  return () => clearTimeout(timeout);
2975
3102
  }
2976
- }, [open, durationMs]);
3103
+ }, [open, isMounted, durationMs]);
2977
3104
  return isMounted;
2978
3105
  }
2979
3106
  /**
@@ -2996,19 +3123,11 @@ function useTransitionStatus(context, props) {
2996
3123
  } = props;
2997
3124
  const isNumberDuration = typeof duration === 'number';
2998
3125
  const closeDuration = (isNumberDuration ? duration : duration.close) || 0;
2999
- const [initiated, setInitiated] = React.useState(false);
3000
3126
  const [status, setStatus] = React.useState('unmounted');
3001
3127
  const isMounted = useDelayUnmount(open, closeDuration);
3002
-
3003
- // `initiated` check prevents this `setState` call from breaking
3004
- // <FloatingPortal />. This call is necessary to ensure subsequent opens
3005
- // after the initial one allows the correct side animation to play when the
3006
- // placement has changed.
3007
- index(() => {
3008
- if (initiated && !isMounted) {
3009
- setStatus('unmounted');
3010
- }
3011
- }, [initiated, isMounted]);
3128
+ if (!isMounted && status === 'close') {
3129
+ setStatus('unmounted');
3130
+ }
3012
3131
  index(() => {
3013
3132
  if (!floating) return;
3014
3133
  if (open) {
@@ -3020,7 +3139,6 @@ function useTransitionStatus(context, props) {
3020
3139
  cancelAnimationFrame(frame);
3021
3140
  };
3022
3141
  }
3023
- setInitiated(true);
3024
3142
  setStatus('close');
3025
3143
  }, [open, floating]);
3026
3144
  return {
@@ -3108,4 +3226,4 @@ function useTransitionStyles(context, props) {
3108
3226
  };
3109
3227
  }
3110
3228
 
3111
- export { FloatingArrow, FloatingFocusManager, FloatingPortal, getOverflowAncestors, platform, useClick, useDismiss, useFloating, useFloatingParentNodeId, useFloatingPortalNode, useFloatingTree, useFocus, useHover, useId, useInteractions, useListNavigation, useMergeRefs, useRole, useTransitionStatus, useTransitionStyles };
3229
+ export { FloatingArrow, FloatingFocusManager, FloatingPortal, getOverflowAncestors, useClick, useDismiss, useFloating, useFloatingParentNodeId, useFloatingPortalNode, useFloatingRootContext, useFloatingTree, useFocus, useHover, useId, useInteractions, useListNavigation, useMergeRefs, useRole, useTransitionStatus, useTransitionStyles };