@primer/components 29.1.0 → 29.1.1-rc.cea79543

Sign up to get free protection for your applications and to get access to all the features.
Files changed (753) hide show
  1. package/.changeset/README.md +8 -0
  2. package/.changeset/config.json +10 -0
  3. package/.devcontainer/devcontainer.json +8 -0
  4. package/.eslintrc.json +106 -0
  5. package/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
  6. package/.github/ISSUE_TEMPLATE/new_component_proposal_template.md +41 -0
  7. package/.github/dependabot.yml +18 -0
  8. package/.github/pull_request_template.md +18 -0
  9. package/.github/workflows/ci.yml +31 -0
  10. package/.github/workflows/deploy_preview.yml +47 -0
  11. package/.github/workflows/deploy_production.yml +70 -0
  12. package/.github/workflows/release.yml +35 -0
  13. package/.github/workflows/release_canary.yml +70 -0
  14. package/.github/workflows/release_candidate.yml +60 -0
  15. package/.github/workflows/size.yml +13 -0
  16. package/.github/workflows/stale.yml +26 -0
  17. package/.gitignore +10 -0
  18. package/.npmrc +4 -0
  19. package/.nvmrc +1 -0
  20. package/.storybook/main.js +11 -0
  21. package/.storybook/preview.js +69 -0
  22. package/.vscode/launch.json +21 -0
  23. package/.vscode/settings.json +13 -0
  24. package/@types/@styled-system/index.d.ts +0 -0
  25. package/@types/@styled-system/prop-types/index.d.ts +1 -0
  26. package/@types/@styled-system/props/index.d.ts +1 -0
  27. package/@types/jest-styled-components/index.d.ts +1 -0
  28. package/CHANGELOG.md +6 -0
  29. package/CODEOWNERS +2 -0
  30. package/babel-defines.js +13 -0
  31. package/babel.config.js +39 -0
  32. package/contributor-docs/CODE_OF_CONDUCT.md +76 -0
  33. package/contributor-docs/CONTRIBUTING.md +274 -0
  34. package/contributor-docs/adrs/adr-001-typescript.md +23 -0
  35. package/contributor-docs/adrs/adr-002-behavior-isolation.md +106 -0
  36. package/contributor-docs/behaviors.md +132 -0
  37. package/contributor-docs/component-contents-api-patterns.md +315 -0
  38. package/contributor-docs/principles.md +39 -0
  39. package/docs/.eslintrc +0 -0
  40. package/docs/.gitignore +91 -0
  41. package/docs/components/PropsList.js +5 -0
  42. package/docs/components/State.js +9 -0
  43. package/docs/components/constants.js +34 -0
  44. package/docs/components/index.js +2 -0
  45. package/docs/content/ActionList.mdx +72 -0
  46. package/docs/content/ActionMenu.mdx +80 -0
  47. package/docs/content/AnchoredOverlay.mdx +37 -0
  48. package/docs/content/Avatar.mdx +33 -0
  49. package/docs/content/AvatarStack.mdx +43 -0
  50. package/docs/content/BorderBox.md +46 -0
  51. package/docs/content/Box.md +74 -0
  52. package/docs/content/BranchName.md +18 -0
  53. package/docs/content/Breadcrumbs.md +52 -0
  54. package/docs/content/Buttons.md +54 -0
  55. package/docs/content/CircleBadge.md +45 -0
  56. package/docs/content/CircleOcticon.md +18 -0
  57. package/docs/content/CounterLabel.md +30 -0
  58. package/docs/content/Details.md +105 -0
  59. package/docs/content/Dialog.md +108 -0
  60. package/docs/content/Dialog2.mdx +179 -0
  61. package/docs/content/Dropdown.md +72 -0
  62. package/docs/content/DropdownMenu.mdx +49 -0
  63. package/docs/content/FilterList.md +44 -0
  64. package/docs/content/FilteredSearch.md +39 -0
  65. package/docs/content/Flash.md +42 -0
  66. package/docs/content/Flex.md +58 -0
  67. package/docs/content/FormGroup.md +44 -0
  68. package/docs/content/Grid.md +59 -0
  69. package/docs/content/Header.md +79 -0
  70. package/docs/content/Heading.md +22 -0
  71. package/docs/content/Label.md +40 -0
  72. package/docs/content/LabelGroup.md +31 -0
  73. package/docs/content/Link.md +37 -0
  74. package/docs/content/Overlay.mdx +94 -0
  75. package/docs/content/Pagehead.md +27 -0
  76. package/docs/content/Pagination.md +187 -0
  77. package/docs/content/PointerBox.md +81 -0
  78. package/docs/content/Popover.md +137 -0
  79. package/docs/content/Portal.mdx +73 -0
  80. package/docs/content/Position.md +97 -0
  81. package/docs/content/ProgressBar.mdx +29 -0
  82. package/docs/content/SelectMenu.md +433 -0
  83. package/docs/content/SelectPanel.mdx +67 -0
  84. package/docs/content/SideNav.md +179 -0
  85. package/docs/content/Spinner.mdx +32 -0
  86. package/docs/content/StateLabel.md +33 -0
  87. package/docs/content/StyledOcticon.md +34 -0
  88. package/docs/content/SubNav.md +102 -0
  89. package/docs/content/TabNav.md +50 -0
  90. package/docs/content/Text.md +29 -0
  91. package/docs/content/TextInput.md +32 -0
  92. package/docs/content/Timeline.md +138 -0
  93. package/docs/content/Tooltip.md +41 -0
  94. package/docs/content/Truncate.md +65 -0
  95. package/docs/content/UnderlineNav.md +53 -0
  96. package/docs/content/anchoredPosition.mdx +163 -0
  97. package/docs/content/core-concepts.md +70 -0
  98. package/docs/content/focusTrap.mdx +103 -0
  99. package/docs/content/focusZone.mdx +145 -0
  100. package/docs/content/getting-started.md +134 -0
  101. package/docs/content/index.md +33 -0
  102. package/docs/content/linting.md +35 -0
  103. package/docs/content/overriding-styles.mdx +79 -0
  104. package/docs/content/philosophy.md +23 -0
  105. package/docs/content/primer-theme.md +89 -0
  106. package/docs/content/ssr.mdx +43 -0
  107. package/docs/content/system-props.mdx +37 -0
  108. package/docs/content/theme-reference.md +16 -0
  109. package/docs/content/theming.md +249 -0
  110. package/docs/content/useOnEscapePress.mdx +56 -0
  111. package/docs/content/useOnOutsideClick.mdx +57 -0
  112. package/docs/content/useOpenAndCloseFocus.mdx +49 -0
  113. package/docs/content/useOverlay.mdx +62 -0
  114. package/docs/content/useSafeTimeout.mdx +32 -0
  115. package/docs/gatsby-config.js +30 -0
  116. package/docs/gatsby-node.js +101 -0
  117. package/docs/package-lock.json +20979 -0
  118. package/docs/package.json +35 -0
  119. package/docs/src/@primer/gatsby-theme-doctocat/components/hero.js +21 -0
  120. package/docs/src/@primer/gatsby-theme-doctocat/components/live-code.js +84 -0
  121. package/docs/src/@primer/gatsby-theme-doctocat/components/live-preview-wrapper.js +39 -0
  122. package/docs/src/@primer/gatsby-theme-doctocat/components/nav-dropdown.js +48 -0
  123. package/docs/src/@primer/gatsby-theme-doctocat/components/wrap-page-element.js +25 -0
  124. package/docs/src/@primer/gatsby-theme-doctocat/live-code-scope.js +54 -0
  125. package/docs/src/@primer/gatsby-theme-doctocat/nav.yml +127 -0
  126. package/docs/src/@primer/gatsby-theme-doctocat/primer-components-hero.svg +1411 -0
  127. package/docs/src/props.js +77 -0
  128. package/jest.config.js +13 -0
  129. package/lib/Button/Button.d.ts +0 -1
  130. package/lib/Button/ButtonClose.d.ts +1 -2
  131. package/lib/Button/ButtonDanger.d.ts +0 -1
  132. package/lib/Button/ButtonInvisible.d.ts +0 -1
  133. package/lib/Button/ButtonOutline.d.ts +0 -1
  134. package/lib/Button/ButtonPrimary.d.ts +0 -1
  135. package/lib/CircleOcticon.d.ts +0 -1
  136. package/lib/Dialog.d.ts +2 -3
  137. package/lib/Dropdown.d.ts +0 -4
  138. package/lib/DropdownMenu/DropdownButton.d.ts +1 -2
  139. package/lib/FilterList.d.ts +0 -1
  140. package/lib/Position.d.ts +4 -4
  141. package/lib/SelectMenu/SelectMenu.d.ts +4 -10
  142. package/lib/SelectMenu/SelectMenuItem.d.ts +1 -1
  143. package/lib/SelectMenu/SelectMenuModal.d.ts +1 -1
  144. package/lib/Timeline.d.ts +0 -1
  145. package/lib/__tests__/ActionList.d.ts +1 -0
  146. package/lib/__tests__/ActionList.js +67 -0
  147. package/lib/__tests__/ActionMenu.d.ts +1 -0
  148. package/lib/__tests__/ActionMenu.js +154 -0
  149. package/lib/__tests__/AnchoredOverlay.d.ts +1 -0
  150. package/lib/__tests__/AnchoredOverlay.js +161 -0
  151. package/lib/__tests__/Avatar.d.ts +1 -0
  152. package/lib/__tests__/Avatar.js +70 -0
  153. package/lib/__tests__/AvatarStack.d.ts +1 -0
  154. package/lib/__tests__/AvatarStack.js +71 -0
  155. package/lib/__tests__/BorderBox.d.ts +1 -0
  156. package/lib/__tests__/BorderBox.js +61 -0
  157. package/lib/__tests__/Box.d.ts +1 -0
  158. package/lib/__tests__/Box.js +81 -0
  159. package/lib/__tests__/BranchName.d.ts +1 -0
  160. package/lib/__tests__/BranchName.js +39 -0
  161. package/lib/__tests__/Breadcrumb.d.ts +1 -0
  162. package/lib/__tests__/Breadcrumb.js +42 -0
  163. package/lib/__tests__/BreadcrumbItem.d.ts +1 -0
  164. package/lib/__tests__/BreadcrumbItem.js +52 -0
  165. package/lib/__tests__/Button.d.ts +1 -0
  166. package/lib/__tests__/Button.js +152 -0
  167. package/lib/__tests__/Caret.d.ts +1 -0
  168. package/lib/__tests__/Caret.js +52 -0
  169. package/lib/__tests__/CircleBadge.d.ts +1 -0
  170. package/lib/__tests__/CircleBadge.js +87 -0
  171. package/lib/__tests__/CircleOcticon.d.ts +1 -0
  172. package/lib/__tests__/CircleOcticon.js +74 -0
  173. package/lib/__tests__/CounterLabel.d.ts +1 -0
  174. package/lib/__tests__/CounterLabel.js +61 -0
  175. package/lib/__tests__/Details.d.ts +1 -0
  176. package/lib/__tests__/Details.js +120 -0
  177. package/lib/__tests__/Dialog.d.ts +1 -0
  178. package/lib/__tests__/Dialog.js +188 -0
  179. package/lib/__tests__/Dropdown.d.ts +1 -0
  180. package/lib/__tests__/Dropdown.js +70 -0
  181. package/lib/__tests__/DropdownMenu.d.ts +1 -0
  182. package/lib/__tests__/DropdownMenu.js +153 -0
  183. package/lib/__tests__/FilterList.d.ts +1 -0
  184. package/lib/__tests__/FilterList.js +39 -0
  185. package/lib/__tests__/FilterListItem.d.ts +1 -0
  186. package/lib/__tests__/FilterListItem.js +49 -0
  187. package/lib/__tests__/FilteredSearch.d.ts +1 -0
  188. package/lib/__tests__/FilteredSearch.js +39 -0
  189. package/lib/__tests__/Flash.d.ts +1 -0
  190. package/lib/__tests__/Flash.js +65 -0
  191. package/lib/__tests__/Flex.d.ts +1 -0
  192. package/lib/__tests__/Flex.js +77 -0
  193. package/lib/__tests__/FormGroup.d.ts +1 -0
  194. package/lib/__tests__/FormGroup.js +58 -0
  195. package/lib/__tests__/Grid.d.ts +1 -0
  196. package/lib/__tests__/Grid.js +107 -0
  197. package/lib/__tests__/Header.d.ts +1 -0
  198. package/lib/__tests__/Header.js +63 -0
  199. package/lib/__tests__/Heading.d.ts +1 -0
  200. package/lib/__tests__/Heading.js +112 -0
  201. package/lib/__tests__/Label.d.ts +1 -0
  202. package/lib/__tests__/Label.js +49 -0
  203. package/lib/__tests__/LabelGroup.d.ts +1 -0
  204. package/lib/__tests__/LabelGroup.js +41 -0
  205. package/lib/__tests__/Link.d.ts +1 -0
  206. package/lib/__tests__/Link.js +73 -0
  207. package/lib/__tests__/Overlay.d.ts +1 -0
  208. package/lib/__tests__/Overlay.js +145 -0
  209. package/lib/__tests__/Pagehead.d.ts +1 -0
  210. package/lib/__tests__/Pagehead.js +40 -0
  211. package/lib/__tests__/Pagination/Pagination.d.ts +1 -0
  212. package/lib/__tests__/Pagination/Pagination.js +50 -0
  213. package/lib/__tests__/Pagination/PaginationModel.d.ts +1 -0
  214. package/lib/__tests__/Pagination/PaginationModel.js +186 -0
  215. package/lib/__tests__/PointerBox.d.ts +1 -0
  216. package/lib/__tests__/PointerBox.js +49 -0
  217. package/lib/__tests__/Popover.d.ts +1 -0
  218. package/lib/__tests__/Popover.js +70 -0
  219. package/lib/__tests__/Portal.d.ts +1 -0
  220. package/lib/__tests__/Portal.js +124 -0
  221. package/lib/__tests__/Position.d.ts +1 -0
  222. package/lib/__tests__/Position.js +149 -0
  223. package/lib/__tests__/ProgressBar.d.ts +1 -0
  224. package/lib/__tests__/ProgressBar.js +71 -0
  225. package/lib/__tests__/SelectMenu.d.ts +1 -0
  226. package/lib/__tests__/SelectMenu.js +155 -0
  227. package/lib/__tests__/SelectPanel.d.ts +1 -0
  228. package/lib/__tests__/SelectPanel.js +83 -0
  229. package/lib/__tests__/SideNav.d.ts +1 -0
  230. package/lib/__tests__/SideNav.js +75 -0
  231. package/lib/__tests__/Spinner.d.ts +1 -0
  232. package/lib/__tests__/Spinner.js +56 -0
  233. package/lib/__tests__/StateLabel.d.ts +1 -0
  234. package/lib/__tests__/StateLabel.js +74 -0
  235. package/lib/__tests__/StyledOcticon.d.ts +1 -0
  236. package/lib/__tests__/StyledOcticon.js +43 -0
  237. package/lib/__tests__/SubNav.d.ts +1 -0
  238. package/lib/__tests__/SubNav.js +65 -0
  239. package/lib/__tests__/SubNavLink.d.ts +1 -0
  240. package/lib/__tests__/SubNavLink.js +52 -0
  241. package/lib/__tests__/TabNav.d.ts +1 -0
  242. package/lib/__tests__/TabNav.js +53 -0
  243. package/lib/__tests__/Text.d.ts +1 -0
  244. package/lib/__tests__/Text.js +108 -0
  245. package/lib/__tests__/TextInput.d.ts +1 -0
  246. package/lib/__tests__/TextInput.js +81 -0
  247. package/lib/__tests__/ThemeProvider.d.ts +1 -0
  248. package/lib/__tests__/ThemeProvider.js +444 -0
  249. package/lib/__tests__/Timeline.d.ts +1 -0
  250. package/lib/__tests__/Timeline.js +80 -0
  251. package/lib/__tests__/Tooltip.d.ts +1 -0
  252. package/lib/__tests__/Tooltip.js +72 -0
  253. package/lib/__tests__/Truncate.d.ts +1 -0
  254. package/lib/__tests__/Truncate.js +66 -0
  255. package/lib/__tests__/UnderlineNav.d.ts +1 -0
  256. package/lib/__tests__/UnderlineNav.js +75 -0
  257. package/lib/__tests__/UnderlineNavLink.d.ts +1 -0
  258. package/lib/__tests__/UnderlineNavLink.js +54 -0
  259. package/lib/__tests__/behaviors/anchoredPosition.d.ts +1 -0
  260. package/lib/__tests__/behaviors/anchoredPosition.js +390 -0
  261. package/lib/__tests__/behaviors/focusTrap.d.ts +1 -0
  262. package/lib/__tests__/behaviors/focusTrap.js +234 -0
  263. package/lib/__tests__/behaviors/focusZone.d.ts +1 -0
  264. package/lib/__tests__/behaviors/focusZone.js +570 -0
  265. package/lib/__tests__/behaviors/iterateFocusableElements.d.ts +1 -0
  266. package/lib/__tests__/behaviors/iterateFocusableElements.js +55 -0
  267. package/lib/__tests__/filterObject.d.ts +1 -0
  268. package/lib/__tests__/filterObject.js +30 -0
  269. package/lib/__tests__/hooks/useAnchoredPosition.d.ts +1 -0
  270. package/lib/__tests__/hooks/useAnchoredPosition.js +54 -0
  271. package/lib/__tests__/hooks/useOnEscapePress.d.ts +1 -0
  272. package/lib/__tests__/hooks/useOnEscapePress.js +32 -0
  273. package/lib/__tests__/hooks/useOnOutsideClick.d.ts +1 -0
  274. package/lib/__tests__/hooks/useOnOutsideClick.js +87 -0
  275. package/lib/__tests__/hooks/useOpenAndCloseFocus.d.ts +1 -0
  276. package/lib/__tests__/hooks/useOpenAndCloseFocus.js +60 -0
  277. package/lib/__tests__/hooks/useProvidedStateOrCreate.d.ts +1 -0
  278. package/lib/__tests__/hooks/useProvidedStateOrCreate.js +45 -0
  279. package/lib/__tests__/theme.d.ts +1 -0
  280. package/lib/__tests__/theme.js +36 -0
  281. package/lib/__tests__/themeGet.d.ts +1 -0
  282. package/lib/__tests__/themeGet.js +25 -0
  283. package/lib/__tests__/useSafeTimeout.d.ts +1 -0
  284. package/lib/__tests__/useSafeTimeout.js +45 -0
  285. package/lib/stories/ActionList.stories.js +382 -0
  286. package/lib/stories/ActionMenu.stories.js +338 -0
  287. package/lib/stories/AnchoredOverlay.stories.js +127 -0
  288. package/lib/stories/AvatarStack.stories.js +49 -0
  289. package/lib/stories/Button.stories.js +114 -0
  290. package/lib/stories/ConfirmationDialog.stories.js +111 -0
  291. package/lib/stories/Dialog.stories.js +265 -0
  292. package/lib/stories/DropdownMenu.stories.js +122 -0
  293. package/lib/stories/Overlay.stories.js +185 -0
  294. package/lib/stories/Portal.stories.js +104 -0
  295. package/lib/stories/SelectPanel.stories.js +342 -0
  296. package/lib/stories/ThemeProvider.stories.js +102 -0
  297. package/lib/stories/useAnchoredPosition.stories.js +351 -0
  298. package/lib/stories/useFocusTrap.stories.js +356 -0
  299. package/lib/stories/useFocusZone.stories.js +599 -0
  300. package/lib-esm/Button/Button.d.ts +0 -1
  301. package/lib-esm/Button/ButtonClose.d.ts +1 -2
  302. package/lib-esm/Button/ButtonDanger.d.ts +0 -1
  303. package/lib-esm/Button/ButtonInvisible.d.ts +0 -1
  304. package/lib-esm/Button/ButtonOutline.d.ts +0 -1
  305. package/lib-esm/Button/ButtonPrimary.d.ts +0 -1
  306. package/lib-esm/CircleOcticon.d.ts +0 -1
  307. package/lib-esm/Dialog.d.ts +2 -3
  308. package/lib-esm/Dropdown.d.ts +0 -4
  309. package/lib-esm/DropdownMenu/DropdownButton.d.ts +1 -2
  310. package/lib-esm/FilterList.d.ts +0 -1
  311. package/lib-esm/Position.d.ts +4 -4
  312. package/lib-esm/SelectMenu/SelectMenu.d.ts +4 -10
  313. package/lib-esm/SelectMenu/SelectMenuItem.d.ts +1 -1
  314. package/lib-esm/SelectMenu/SelectMenuModal.d.ts +1 -1
  315. package/lib-esm/Timeline.d.ts +0 -1
  316. package/lib-esm/__tests__/ActionList.d.ts +1 -0
  317. package/lib-esm/__tests__/ActionList.js +54 -0
  318. package/lib-esm/__tests__/ActionMenu.d.ts +1 -0
  319. package/lib-esm/__tests__/ActionMenu.js +141 -0
  320. package/lib-esm/__tests__/AnchoredOverlay.d.ts +1 -0
  321. package/lib-esm/__tests__/AnchoredOverlay.js +135 -0
  322. package/lib-esm/__tests__/Avatar.d.ts +1 -0
  323. package/lib-esm/__tests__/Avatar.js +58 -0
  324. package/lib-esm/__tests__/AvatarStack.d.ts +1 -0
  325. package/lib-esm/__tests__/AvatarStack.js +57 -0
  326. package/lib-esm/__tests__/BorderBox.d.ts +1 -0
  327. package/lib-esm/__tests__/BorderBox.js +49 -0
  328. package/lib-esm/__tests__/Box.d.ts +1 -0
  329. package/lib-esm/__tests__/Box.js +69 -0
  330. package/lib-esm/__tests__/BranchName.d.ts +1 -0
  331. package/lib-esm/__tests__/BranchName.js +28 -0
  332. package/lib-esm/__tests__/Breadcrumb.d.ts +1 -0
  333. package/lib-esm/__tests__/Breadcrumb.js +31 -0
  334. package/lib-esm/__tests__/BreadcrumbItem.d.ts +1 -0
  335. package/lib-esm/__tests__/BreadcrumbItem.js +41 -0
  336. package/lib-esm/__tests__/Button.d.ts +1 -0
  337. package/lib-esm/__tests__/Button.js +141 -0
  338. package/lib-esm/__tests__/Caret.d.ts +1 -0
  339. package/lib-esm/__tests__/Caret.js +42 -0
  340. package/lib-esm/__tests__/CircleBadge.d.ts +1 -0
  341. package/lib-esm/__tests__/CircleBadge.js +73 -0
  342. package/lib-esm/__tests__/CircleOcticon.d.ts +1 -0
  343. package/lib-esm/__tests__/CircleOcticon.js +61 -0
  344. package/lib-esm/__tests__/CounterLabel.d.ts +1 -0
  345. package/lib-esm/__tests__/CounterLabel.js +49 -0
  346. package/lib-esm/__tests__/Details.d.ts +1 -0
  347. package/lib-esm/__tests__/Details.js +109 -0
  348. package/lib-esm/__tests__/Dialog.d.ts +1 -0
  349. package/lib-esm/__tests__/Dialog.js +174 -0
  350. package/lib-esm/__tests__/Dropdown.d.ts +1 -0
  351. package/lib-esm/__tests__/Dropdown.js +59 -0
  352. package/lib-esm/__tests__/DropdownMenu.d.ts +1 -0
  353. package/lib-esm/__tests__/DropdownMenu.js +139 -0
  354. package/lib-esm/__tests__/FilterList.d.ts +1 -0
  355. package/lib-esm/__tests__/FilterList.js +28 -0
  356. package/lib-esm/__tests__/FilterListItem.d.ts +1 -0
  357. package/lib-esm/__tests__/FilterListItem.js +38 -0
  358. package/lib-esm/__tests__/FilteredSearch.d.ts +1 -0
  359. package/lib-esm/__tests__/FilteredSearch.js +28 -0
  360. package/lib-esm/__tests__/Flash.d.ts +1 -0
  361. package/lib-esm/__tests__/Flash.js +53 -0
  362. package/lib-esm/__tests__/Flex.d.ts +1 -0
  363. package/lib-esm/__tests__/Flex.js +66 -0
  364. package/lib-esm/__tests__/FormGroup.d.ts +1 -0
  365. package/lib-esm/__tests__/FormGroup.js +47 -0
  366. package/lib-esm/__tests__/Grid.d.ts +1 -0
  367. package/lib-esm/__tests__/Grid.js +96 -0
  368. package/lib-esm/__tests__/Header.d.ts +1 -0
  369. package/lib-esm/__tests__/Header.js +52 -0
  370. package/lib-esm/__tests__/Heading.d.ts +1 -0
  371. package/lib-esm/__tests__/Heading.js +101 -0
  372. package/lib-esm/__tests__/Label.d.ts +1 -0
  373. package/lib-esm/__tests__/Label.js +38 -0
  374. package/lib-esm/__tests__/LabelGroup.d.ts +1 -0
  375. package/lib-esm/__tests__/LabelGroup.js +28 -0
  376. package/lib-esm/__tests__/Link.d.ts +1 -0
  377. package/lib-esm/__tests__/Link.js +62 -0
  378. package/lib-esm/__tests__/Overlay.d.ts +1 -0
  379. package/lib-esm/__tests__/Overlay.js +123 -0
  380. package/lib-esm/__tests__/Pagehead.d.ts +1 -0
  381. package/lib-esm/__tests__/Pagehead.js +28 -0
  382. package/lib-esm/__tests__/Pagination/Pagination.d.ts +1 -0
  383. package/lib-esm/__tests__/Pagination/Pagination.js +37 -0
  384. package/lib-esm/__tests__/Pagination/PaginationModel.d.ts +1 -0
  385. package/lib-esm/__tests__/Pagination/PaginationModel.js +182 -0
  386. package/lib-esm/__tests__/PointerBox.d.ts +1 -0
  387. package/lib-esm/__tests__/PointerBox.js +38 -0
  388. package/lib-esm/__tests__/Popover.d.ts +1 -0
  389. package/lib-esm/__tests__/Popover.js +56 -0
  390. package/lib-esm/__tests__/Portal.d.ts +1 -0
  391. package/lib-esm/__tests__/Portal.js +104 -0
  392. package/lib-esm/__tests__/Position.d.ts +1 -0
  393. package/lib-esm/__tests__/Position.js +138 -0
  394. package/lib-esm/__tests__/ProgressBar.d.ts +1 -0
  395. package/lib-esm/__tests__/ProgressBar.js +60 -0
  396. package/lib-esm/__tests__/SelectMenu.d.ts +1 -0
  397. package/lib-esm/__tests__/SelectMenu.js +145 -0
  398. package/lib-esm/__tests__/SelectPanel.d.ts +1 -0
  399. package/lib-esm/__tests__/SelectPanel.js +67 -0
  400. package/lib-esm/__tests__/SideNav.d.ts +1 -0
  401. package/lib-esm/__tests__/SideNav.js +63 -0
  402. package/lib-esm/__tests__/Spinner.d.ts +1 -0
  403. package/lib-esm/__tests__/Spinner.js +45 -0
  404. package/lib-esm/__tests__/StateLabel.d.ts +1 -0
  405. package/lib-esm/__tests__/StateLabel.js +63 -0
  406. package/lib-esm/__tests__/StyledOcticon.d.ts +1 -0
  407. package/lib-esm/__tests__/StyledOcticon.js +31 -0
  408. package/lib-esm/__tests__/SubNav.d.ts +1 -0
  409. package/lib-esm/__tests__/SubNav.js +52 -0
  410. package/lib-esm/__tests__/SubNavLink.d.ts +1 -0
  411. package/lib-esm/__tests__/SubNavLink.js +41 -0
  412. package/lib-esm/__tests__/TabNav.d.ts +1 -0
  413. package/lib-esm/__tests__/TabNav.js +42 -0
  414. package/lib-esm/__tests__/Text.d.ts +1 -0
  415. package/lib-esm/__tests__/Text.js +95 -0
  416. package/lib-esm/__tests__/TextInput.d.ts +1 -0
  417. package/lib-esm/__tests__/TextInput.js +70 -0
  418. package/lib-esm/__tests__/ThemeProvider.d.ts +1 -0
  419. package/lib-esm/__tests__/ThemeProvider.js +408 -0
  420. package/lib-esm/__tests__/Timeline.d.ts +1 -0
  421. package/lib-esm/__tests__/Timeline.js +69 -0
  422. package/lib-esm/__tests__/Tooltip.d.ts +1 -0
  423. package/lib-esm/__tests__/Tooltip.js +61 -0
  424. package/lib-esm/__tests__/Truncate.d.ts +1 -0
  425. package/lib-esm/__tests__/Truncate.js +55 -0
  426. package/lib-esm/__tests__/UnderlineNav.d.ts +1 -0
  427. package/lib-esm/__tests__/UnderlineNav.js +62 -0
  428. package/lib-esm/__tests__/UnderlineNavLink.d.ts +1 -0
  429. package/lib-esm/__tests__/UnderlineNavLink.js +43 -0
  430. package/lib-esm/__tests__/behaviors/anchoredPosition.d.ts +1 -0
  431. package/lib-esm/__tests__/behaviors/anchoredPosition.js +388 -0
  432. package/lib-esm/__tests__/behaviors/focusTrap.d.ts +1 -0
  433. package/lib-esm/__tests__/behaviors/focusTrap.js +227 -0
  434. package/lib-esm/__tests__/behaviors/focusZone.d.ts +1 -0
  435. package/lib-esm/__tests__/behaviors/focusZone.js +487 -0
  436. package/lib-esm/__tests__/behaviors/iterateFocusableElements.d.ts +1 -0
  437. package/lib-esm/__tests__/behaviors/iterateFocusableElements.js +48 -0
  438. package/lib-esm/__tests__/filterObject.d.ts +1 -0
  439. package/lib-esm/__tests__/filterObject.js +27 -0
  440. package/lib-esm/__tests__/hooks/useAnchoredPosition.d.ts +1 -0
  441. package/lib-esm/__tests__/hooks/useAnchoredPosition.js +46 -0
  442. package/lib-esm/__tests__/hooks/useOnEscapePress.d.ts +1 -0
  443. package/lib-esm/__tests__/hooks/useOnEscapePress.js +23 -0
  444. package/lib-esm/__tests__/hooks/useOnOutsideClick.d.ts +1 -0
  445. package/lib-esm/__tests__/hooks/useOnOutsideClick.js +68 -0
  446. package/lib-esm/__tests__/hooks/useOpenAndCloseFocus.d.ts +1 -0
  447. package/lib-esm/__tests__/hooks/useOpenAndCloseFocus.js +52 -0
  448. package/lib-esm/__tests__/hooks/useProvidedStateOrCreate.d.ts +1 -0
  449. package/lib-esm/__tests__/hooks/useProvidedStateOrCreate.js +36 -0
  450. package/lib-esm/__tests__/theme.d.ts +1 -0
  451. package/lib-esm/__tests__/theme.js +33 -0
  452. package/lib-esm/__tests__/themeGet.d.ts +1 -0
  453. package/lib-esm/__tests__/themeGet.js +22 -0
  454. package/lib-esm/__tests__/useSafeTimeout.d.ts +1 -0
  455. package/lib-esm/__tests__/useSafeTimeout.js +39 -0
  456. package/lib-esm/stories/ActionList.stories.js +334 -0
  457. package/lib-esm/stories/ActionMenu.stories.js +293 -0
  458. package/lib-esm/stories/AnchoredOverlay.stories.js +101 -0
  459. package/lib-esm/stories/AvatarStack.stories.js +32 -0
  460. package/lib-esm/stories/Button.stories.js +78 -0
  461. package/lib-esm/stories/ConfirmationDialog.stories.js +86 -0
  462. package/lib-esm/stories/Dialog.stories.js +240 -0
  463. package/lib-esm/stories/DropdownMenu.stories.js +94 -0
  464. package/lib-esm/stories/Overlay.stories.js +154 -0
  465. package/lib-esm/stories/Portal.stories.js +68 -0
  466. package/lib-esm/stories/SelectPanel.stories.js +284 -0
  467. package/lib-esm/stories/ThemeProvider.stories.js +83 -0
  468. package/lib-esm/stories/useAnchoredPosition.stories.js +313 -0
  469. package/lib-esm/stories/useFocusTrap.stories.js +309 -0
  470. package/lib-esm/stories/useFocusZone.stories.js +554 -0
  471. package/migrating.md +250 -0
  472. package/now.json +17 -0
  473. package/package-lock.json +28661 -0
  474. package/package.json +2 -2
  475. package/rollup.config.js +36 -0
  476. package/script/build +19 -0
  477. package/script/setup +12 -0
  478. package/src/ActionList/Divider.tsx +25 -0
  479. package/src/ActionList/Group.tsx +45 -0
  480. package/src/ActionList/Header.tsx +74 -0
  481. package/src/ActionList/Item.tsx +460 -0
  482. package/src/ActionList/List.tsx +253 -0
  483. package/src/ActionList/index.ts +21 -0
  484. package/src/ActionMenu.tsx +106 -0
  485. package/src/AnchoredOverlay/AnchoredOverlay.tsx +180 -0
  486. package/src/AnchoredOverlay/index.ts +2 -0
  487. package/src/Avatar.tsx +46 -0
  488. package/src/AvatarPair.tsx +35 -0
  489. package/src/AvatarStack.tsx +161 -0
  490. package/src/BaseStyles.tsx +53 -0
  491. package/src/BorderBox.tsx +18 -0
  492. package/src/Box.tsx +54 -0
  493. package/src/BranchName.tsx +19 -0
  494. package/src/Breadcrumb.tsx +87 -0
  495. package/src/Button/Button.tsx +40 -0
  496. package/src/Button/ButtonBase.tsx +43 -0
  497. package/src/Button/ButtonClose.tsx +40 -0
  498. package/src/Button/ButtonDanger.tsx +43 -0
  499. package/src/Button/ButtonGroup.tsx +55 -0
  500. package/src/Button/ButtonInvisible.tsx +27 -0
  501. package/src/Button/ButtonOutline.tsx +43 -0
  502. package/src/Button/ButtonPrimary.tsx +41 -0
  503. package/src/Button/ButtonStyles.tsx +36 -0
  504. package/src/Button/ButtonTableList.tsx +58 -0
  505. package/src/Button/index.ts +16 -0
  506. package/src/Caret.tsx +133 -0
  507. package/src/CircleBadge.tsx +55 -0
  508. package/src/CircleOcticon.tsx +37 -0
  509. package/src/CounterLabel.tsx +52 -0
  510. package/src/Details.tsx +23 -0
  511. package/src/Dialog/ConfirmationDialog.tsx +184 -0
  512. package/src/Dialog/Dialog.tsx +419 -0
  513. package/src/Dialog.tsx +149 -0
  514. package/src/Dropdown.tsx +158 -0
  515. package/src/DropdownMenu/DropdownButton.tsx +15 -0
  516. package/src/DropdownMenu/DropdownMenu.tsx +115 -0
  517. package/src/DropdownMenu/index.ts +4 -0
  518. package/src/DropdownStyles.ts +128 -0
  519. package/src/FilterList.tsx +81 -0
  520. package/src/FilteredActionList/FilteredActionList.tsx +152 -0
  521. package/src/FilteredActionList/index.ts +2 -0
  522. package/src/FilteredSearch.tsx +28 -0
  523. package/src/Flash.tsx +77 -0
  524. package/src/Flex.tsx +15 -0
  525. package/src/FormGroup.tsx +27 -0
  526. package/src/Grid.tsx +15 -0
  527. package/src/Header.tsx +84 -0
  528. package/src/Heading.tsx +21 -0
  529. package/src/Label.tsx +75 -0
  530. package/src/LabelGroup.tsx +18 -0
  531. package/src/Link.tsx +46 -0
  532. package/src/Overlay.tsx +194 -0
  533. package/src/Pagehead.tsx +17 -0
  534. package/src/Pagination/Pagination.tsx +214 -0
  535. package/src/Pagination/index.ts +4 -0
  536. package/src/Pagination/model.tsx +187 -0
  537. package/src/PointerBox.tsx +31 -0
  538. package/src/Popover.tsx +236 -0
  539. package/src/Portal/Portal.tsx +96 -0
  540. package/src/Portal/index.ts +5 -0
  541. package/src/Position.tsx +63 -0
  542. package/src/ProgressBar.tsx +52 -0
  543. package/src/SelectMenu/SelectMenu.tsx +125 -0
  544. package/src/SelectMenu/SelectMenuContext.tsx +9 -0
  545. package/src/SelectMenu/SelectMenuDivider.tsx +25 -0
  546. package/src/SelectMenu/SelectMenuFilter.tsx +51 -0
  547. package/src/SelectMenu/SelectMenuFooter.tsx +28 -0
  548. package/src/SelectMenu/SelectMenuHeader.tsx +50 -0
  549. package/src/SelectMenu/SelectMenuItem.tsx +137 -0
  550. package/src/SelectMenu/SelectMenuList.tsx +42 -0
  551. package/src/SelectMenu/SelectMenuLoadingAnimation.tsx +24 -0
  552. package/src/SelectMenu/SelectMenuModal.tsx +121 -0
  553. package/src/SelectMenu/SelectMenuTab.tsx +88 -0
  554. package/src/SelectMenu/SelectMenuTabPanel.tsx +30 -0
  555. package/src/SelectMenu/SelectMenuTabs.tsx +44 -0
  556. package/src/SelectMenu/hooks/useKeyboardNav.js +90 -0
  557. package/src/SelectMenu/index.ts +15 -0
  558. package/src/SelectPanel/SelectPanel.tsx +173 -0
  559. package/src/SelectPanel/index.ts +2 -0
  560. package/src/SideNav.tsx +193 -0
  561. package/src/Spinner.tsx +59 -0
  562. package/src/StateLabel.tsx +110 -0
  563. package/src/StyledOcticon.tsx +24 -0
  564. package/src/SubNav.tsx +129 -0
  565. package/src/TabNav.tsx +77 -0
  566. package/src/Text.tsx +13 -0
  567. package/src/TextInput.tsx +183 -0
  568. package/src/ThemeProvider.tsx +176 -0
  569. package/src/Timeline.tsx +141 -0
  570. package/src/Tooltip.tsx +263 -0
  571. package/src/Truncate.tsx +36 -0
  572. package/src/UnderlineNav.tsx +110 -0
  573. package/src/__tests__/.eslintrc.json +11 -0
  574. package/src/__tests__/ActionList.tsx +49 -0
  575. package/src/__tests__/ActionMenu.tsx +138 -0
  576. package/src/__tests__/AnchoredOverlay.tsx +151 -0
  577. package/src/__tests__/Avatar.tsx +45 -0
  578. package/src/__tests__/AvatarStack.tsx +45 -0
  579. package/src/__tests__/BorderBox.tsx +44 -0
  580. package/src/__tests__/Box.tsx +43 -0
  581. package/src/__tests__/BranchName.tsx +27 -0
  582. package/src/__tests__/Breadcrumb.tsx +31 -0
  583. package/src/__tests__/BreadcrumbItem.tsx +32 -0
  584. package/src/__tests__/Button.tsx +129 -0
  585. package/src/__tests__/Caret.tsx +36 -0
  586. package/src/__tests__/CircleBadge.tsx +69 -0
  587. package/src/__tests__/CircleOcticon.tsx +52 -0
  588. package/src/__tests__/CounterLabel.tsx +51 -0
  589. package/src/__tests__/Details.tsx +116 -0
  590. package/src/__tests__/Dialog.tsx +157 -0
  591. package/src/__tests__/Dropdown.tsx +57 -0
  592. package/src/__tests__/DropdownMenu.tsx +138 -0
  593. package/src/__tests__/FilterList.tsx +27 -0
  594. package/src/__tests__/FilterListItem.tsx +32 -0
  595. package/src/__tests__/FilteredSearch.tsx +27 -0
  596. package/src/__tests__/Flash.tsx +46 -0
  597. package/src/__tests__/Flex.tsx +59 -0
  598. package/src/__tests__/FormGroup.tsx +39 -0
  599. package/src/__tests__/Grid.tsx +83 -0
  600. package/src/__tests__/Header.tsx +50 -0
  601. package/src/__tests__/Heading.tsx +92 -0
  602. package/src/__tests__/Label.tsx +35 -0
  603. package/src/__tests__/LabelGroup.tsx +31 -0
  604. package/src/__tests__/Link.tsx +48 -0
  605. package/src/__tests__/Overlay.tsx +103 -0
  606. package/src/__tests__/Pagehead.tsx +24 -0
  607. package/src/__tests__/Pagination/Pagination.tsx +31 -0
  608. package/src/__tests__/Pagination/PaginationModel.tsx +133 -0
  609. package/src/__tests__/Pagination/__snapshots__/Pagination.tsx.snap +184 -0
  610. package/src/__tests__/PointerBox.tsx +35 -0
  611. package/src/__tests__/Popover.tsx +69 -0
  612. package/src/__tests__/Portal.tsx +103 -0
  613. package/src/__tests__/Position.tsx +118 -0
  614. package/src/__tests__/ProgressBar.tsx +41 -0
  615. package/src/__tests__/SelectMenu.tsx +142 -0
  616. package/src/__tests__/SelectPanel.tsx +65 -0
  617. package/src/__tests__/SideNav.tsx +63 -0
  618. package/src/__tests__/Spinner.tsx +44 -0
  619. package/src/__tests__/StateLabel.tsx +50 -0
  620. package/src/__tests__/StyledOcticon.tsx +28 -0
  621. package/src/__tests__/SubNav.tsx +51 -0
  622. package/src/__tests__/SubNavLink.tsx +32 -0
  623. package/src/__tests__/TabNav.tsx +33 -0
  624. package/src/__tests__/Text.tsx +79 -0
  625. package/src/__tests__/TextInput.tsx +50 -0
  626. package/src/__tests__/ThemeProvider.tsx +441 -0
  627. package/src/__tests__/Timeline.tsx +59 -0
  628. package/src/__tests__/Tooltip.tsx +53 -0
  629. package/src/__tests__/Truncate.tsx +45 -0
  630. package/src/__tests__/UnderlineNav.tsx +59 -0
  631. package/src/__tests__/UnderlineNavLink.tsx +32 -0
  632. package/src/__tests__/__snapshots__/ActionList.tsx.snap +27 -0
  633. package/src/__tests__/__snapshots__/ActionMenu.tsx.snap +80 -0
  634. package/src/__tests__/__snapshots__/AnchoredOverlay.tsx.snap +332 -0
  635. package/src/__tests__/__snapshots__/Avatar.tsx.snap +19 -0
  636. package/src/__tests__/__snapshots__/AvatarStack.tsx.snap +377 -0
  637. package/src/__tests__/__snapshots__/BorderBox.tsx.snap +14 -0
  638. package/src/__tests__/__snapshots__/Box.tsx.snap +201 -0
  639. package/src/__tests__/__snapshots__/BranchName.tsx.snap +17 -0
  640. package/src/__tests__/__snapshots__/Breadcrumb.tsx.snap +29 -0
  641. package/src/__tests__/__snapshots__/BreadcrumbItem.tsx.snap +79 -0
  642. package/src/__tests__/__snapshots__/Button.tsx.snap +832 -0
  643. package/src/__tests__/__snapshots__/Caret.tsx.snap +373 -0
  644. package/src/__tests__/__snapshots__/CircleBadge.tsx.snap +141 -0
  645. package/src/__tests__/__snapshots__/CircleOcticon.tsx.snap +64 -0
  646. package/src/__tests__/__snapshots__/CounterLabel.tsx.snap +22 -0
  647. package/src/__tests__/__snapshots__/Details.tsx.snap +15 -0
  648. package/src/__tests__/__snapshots__/Dialog.tsx.snap +200 -0
  649. package/src/__tests__/__snapshots__/Dropdown.tsx.snap +249 -0
  650. package/src/__tests__/__snapshots__/DropdownMenu.tsx.snap +106 -0
  651. package/src/__tests__/__snapshots__/FilterList.tsx.snap +13 -0
  652. package/src/__tests__/__snapshots__/FilterListItem.tsx.snap +80 -0
  653. package/src/__tests__/__snapshots__/FilteredSearch.tsx.snap +32 -0
  654. package/src/__tests__/__snapshots__/Flash.tsx.snap +32 -0
  655. package/src/__tests__/__snapshots__/Flex.tsx.snap +130 -0
  656. package/src/__tests__/__snapshots__/FormGroup.tsx.snap +25 -0
  657. package/src/__tests__/__snapshots__/Grid.tsx.snap +178 -0
  658. package/src/__tests__/__snapshots__/Header.tsx.snap +79 -0
  659. package/src/__tests__/__snapshots__/Heading.tsx.snap +13 -0
  660. package/src/__tests__/__snapshots__/Label.tsx.snap +74 -0
  661. package/src/__tests__/__snapshots__/LabelGroup.tsx.snap +15 -0
  662. package/src/__tests__/__snapshots__/Link.tsx.snap +213 -0
  663. package/src/__tests__/__snapshots__/Pagehead.tsx.snap +15 -0
  664. package/src/__tests__/__snapshots__/PointerBox.tsx.snap +174 -0
  665. package/src/__tests__/__snapshots__/Popover.tsx.snap +4687 -0
  666. package/src/__tests__/__snapshots__/Position.tsx.snap +44 -0
  667. package/src/__tests__/__snapshots__/ProgressBar.tsx.snap +53 -0
  668. package/src/__tests__/__snapshots__/SelectMenu.tsx.snap +469 -0
  669. package/src/__tests__/__snapshots__/SelectPanel.tsx.snap +123 -0
  670. package/src/__tests__/__snapshots__/SideNav.tsx.snap +143 -0
  671. package/src/__tests__/__snapshots__/Spinner.tsx.snap +33 -0
  672. package/src/__tests__/__snapshots__/StateLabel.tsx.snap +409 -0
  673. package/src/__tests__/__snapshots__/StyledOcticon.tsx.snap +25 -0
  674. package/src/__tests__/__snapshots__/SubNav.tsx.snap +44 -0
  675. package/src/__tests__/__snapshots__/SubNavLink.tsx.snap +199 -0
  676. package/src/__tests__/__snapshots__/TabNav.tsx.snap +58 -0
  677. package/src/__tests__/__snapshots__/Text.tsx.snap +7 -0
  678. package/src/__tests__/__snapshots__/TextInput.tsx.snap +440 -0
  679. package/src/__tests__/__snapshots__/ThemeProvider.tsx.snap +15 -0
  680. package/src/__tests__/__snapshots__/Timeline.tsx.snap +159 -0
  681. package/src/__tests__/__snapshots__/Tooltip.tsx.snap +227 -0
  682. package/src/__tests__/__snapshots__/Truncate.tsx.snap +17 -0
  683. package/src/__tests__/__snapshots__/UnderlineNav.tsx.snap +59 -0
  684. package/src/__tests__/__snapshots__/UnderlineNavLink.tsx.snap +130 -0
  685. package/src/__tests__/behaviors/anchoredPosition.ts +295 -0
  686. package/src/__tests__/behaviors/focusTrap.tsx +236 -0
  687. package/src/__tests__/behaviors/focusZone.tsx +549 -0
  688. package/src/__tests__/behaviors/iterateFocusableElements.tsx +61 -0
  689. package/src/__tests__/filterObject.ts +54 -0
  690. package/src/__tests__/hooks/useAnchoredPosition.tsx +31 -0
  691. package/src/__tests__/hooks/useOnEscapePress.tsx +16 -0
  692. package/src/__tests__/hooks/useOnOutsideClick.tsx +48 -0
  693. package/src/__tests__/hooks/useOpenAndCloseFocus.tsx +48 -0
  694. package/src/__tests__/hooks/useProvidedStateOrCreate.tsx +39 -0
  695. package/src/__tests__/theme.ts +41 -0
  696. package/src/__tests__/themeGet.ts +15 -0
  697. package/src/__tests__/useSafeTimeout.tsx +36 -0
  698. package/src/behaviors/anchoredPosition.ts +442 -0
  699. package/src/behaviors/focusTrap.ts +184 -0
  700. package/src/behaviors/focusZone.ts +713 -0
  701. package/src/constants.ts +62 -0
  702. package/src/hooks/index.ts +11 -0
  703. package/src/hooks/useAnchoredPosition.ts +53 -0
  704. package/src/hooks/useCombinedRefs.ts +40 -0
  705. package/src/hooks/useDetails.tsx +54 -0
  706. package/src/hooks/useDialog.ts +121 -0
  707. package/src/hooks/useFocusTrap.ts +80 -0
  708. package/src/hooks/useFocusZone.ts +64 -0
  709. package/src/hooks/useOnEscapePress.ts +63 -0
  710. package/src/hooks/useOnOutsideClick.tsx +82 -0
  711. package/src/hooks/useOpenAndCloseFocus.ts +27 -0
  712. package/src/hooks/useOverlay.tsx +32 -0
  713. package/src/hooks/useProvidedRefOrCreate.ts +14 -0
  714. package/src/hooks/useProvidedStateOrCreate.ts +27 -0
  715. package/src/hooks/useRenderForcingRef.ts +22 -0
  716. package/src/hooks/useResizeObserver.ts +11 -0
  717. package/src/hooks/useSafeTimeout.ts +38 -0
  718. package/src/hooks/useScrollFlash.ts +21 -0
  719. package/src/index.ts +165 -0
  720. package/src/polyfills/eventListenerSignal.ts +66 -0
  721. package/src/stories/ActionList.stories.tsx +364 -0
  722. package/src/stories/ActionMenu.stories.tsx +322 -0
  723. package/src/stories/AnchoredOverlay.stories.tsx +117 -0
  724. package/src/stories/AvatarStack.stories.tsx +37 -0
  725. package/src/stories/Button.stories.tsx +88 -0
  726. package/src/stories/ConfirmationDialog.stories.tsx +105 -0
  727. package/src/stories/Dialog.stories.tsx +240 -0
  728. package/src/stories/DropdownMenu.stories.tsx +84 -0
  729. package/src/stories/Overlay.stories.tsx +186 -0
  730. package/src/stories/Portal.stories.tsx +109 -0
  731. package/src/stories/SelectPanel.stories.tsx +300 -0
  732. package/src/stories/ThemeProvider.stories.tsx +104 -0
  733. package/src/stories/useAnchoredPosition.stories.tsx +320 -0
  734. package/src/stories/useFocusTrap.stories.tsx +400 -0
  735. package/src/stories/useFocusZone.stories.tsx +663 -0
  736. package/src/sx.ts +9 -0
  737. package/src/theme-preval.js +136 -0
  738. package/src/theme.ts +3 -0
  739. package/src/utils/deprecate.tsx +73 -0
  740. package/src/utils/isNumeric.tsx +4 -0
  741. package/src/utils/iterateFocusableElements.ts +121 -0
  742. package/src/utils/ssr.tsx +1 -0
  743. package/src/utils/test-deprecations.tsx +19 -0
  744. package/src/utils/test-helpers.tsx +7 -0
  745. package/src/utils/test-matchers.tsx +109 -0
  746. package/src/utils/testing.tsx +243 -0
  747. package/src/utils/theme.js +64 -0
  748. package/src/utils/types.ts +90 -0
  749. package/src/utils/uniqueId.ts +6 -0
  750. package/src/utils/userAgent.ts +7 -0
  751. package/stats.html +3279 -0
  752. package/tsconfig.build.json +7 -0
  753. package/tsconfig.json +20 -0
@@ -0,0 +1,713 @@
1
+ import {iterateFocusableElements} from '../utils/iterateFocusableElements'
2
+ import {polyfill as eventListenerSignalPolyfill} from '../polyfills/eventListenerSignal'
3
+ import {isMacOS} from '../utils/userAgent'
4
+ import {uniqueId} from '../utils/uniqueId'
5
+
6
+ eventListenerSignalPolyfill()
7
+
8
+ export type Direction = 'previous' | 'next' | 'start' | 'end'
9
+
10
+ export type FocusMovementKeys =
11
+ | 'ArrowLeft'
12
+ | 'ArrowDown'
13
+ | 'ArrowUp'
14
+ | 'ArrowRight'
15
+ | 'h'
16
+ | 'j'
17
+ | 'k'
18
+ | 'l'
19
+ | 'a'
20
+ | 's'
21
+ | 'w'
22
+ | 'd'
23
+ | 'Tab'
24
+ | 'Home'
25
+ | 'End'
26
+ | 'PageUp'
27
+ | 'PageDown'
28
+
29
+ // eslint-disable-next-line no-shadow
30
+ export enum FocusKeys {
31
+ // Left and right arrow keys (previous and next, respectively)
32
+ ArrowHorizontal = 0b000000001,
33
+
34
+ // Up and down arrow keys (previous and next, respectively)
35
+ ArrowVertical = 0b000000010,
36
+
37
+ // The "J" and "K" keys (next and previous, respectively)
38
+ JK = 0b000000100,
39
+
40
+ // The "H" and "L" keys (previous and next, respectively)
41
+ HL = 0b000001000,
42
+
43
+ // The Home and End keys (previous and next, respectively, to end)
44
+ HomeAndEnd = 0b000010000,
45
+
46
+ // The PgUp and PgDn keys (previous and next, respectively, to end)
47
+ PageUpDown = 0b100000000,
48
+
49
+ // The "W" and "S" keys (previous and next, respectively)
50
+ WS = 0b000100000,
51
+
52
+ // The "A" and "D" keys (previous and next, respectively)
53
+ AD = 0b001000000,
54
+
55
+ // The Tab key (next)
56
+ Tab = 0b010000000,
57
+
58
+ ArrowAll = FocusKeys.ArrowHorizontal | FocusKeys.ArrowVertical,
59
+ HJKL = FocusKeys.HL | FocusKeys.JK,
60
+ WASD = FocusKeys.WS | FocusKeys.AD,
61
+ All = FocusKeys.ArrowAll |
62
+ FocusKeys.HJKL |
63
+ FocusKeys.HomeAndEnd |
64
+ FocusKeys.PageUpDown |
65
+ FocusKeys.WASD |
66
+ FocusKeys.Tab
67
+ }
68
+
69
+ const KEY_TO_BIT = {
70
+ ArrowLeft: FocusKeys.ArrowHorizontal,
71
+ ArrowDown: FocusKeys.ArrowVertical,
72
+ ArrowUp: FocusKeys.ArrowVertical,
73
+ ArrowRight: FocusKeys.ArrowHorizontal,
74
+ h: FocusKeys.HL,
75
+ j: FocusKeys.JK,
76
+ k: FocusKeys.JK,
77
+ l: FocusKeys.HL,
78
+ a: FocusKeys.AD,
79
+ s: FocusKeys.WS,
80
+ w: FocusKeys.WS,
81
+ d: FocusKeys.AD,
82
+ Tab: FocusKeys.Tab,
83
+ Home: FocusKeys.HomeAndEnd,
84
+ End: FocusKeys.HomeAndEnd,
85
+ PageUp: FocusKeys.PageUpDown,
86
+ PageDown: FocusKeys.PageUpDown
87
+ } as {[k in FocusMovementKeys]: FocusKeys}
88
+
89
+ const KEY_TO_DIRECTION = {
90
+ ArrowLeft: 'previous',
91
+ ArrowDown: 'next',
92
+ ArrowUp: 'previous',
93
+ ArrowRight: 'next',
94
+ h: 'previous',
95
+ j: 'next',
96
+ k: 'previous',
97
+ l: 'next',
98
+ a: 'previous',
99
+ s: 'next',
100
+ w: 'previous',
101
+ d: 'next',
102
+ Tab: 'next',
103
+ Home: 'start',
104
+ End: 'end',
105
+ PageUp: 'start',
106
+ PageDown: 'end'
107
+ } as {[k in FocusMovementKeys]: Direction}
108
+
109
+ /**
110
+ * Options that control the behavior of the arrow focus behavior.
111
+ */
112
+ export interface FocusZoneSettings {
113
+ /**
114
+ * Choose the behavior applied in cases where focus is currently at either the first or
115
+ * last element of the container.
116
+ *
117
+ * "stop" - do nothing and keep focus where it was
118
+ * "wrap" - wrap focus around to the first element from the last, or the last element from the first
119
+ *
120
+ * Default: "stop"
121
+ */
122
+ focusOutBehavior?: 'stop' | 'wrap'
123
+
124
+ /**
125
+ * If set, this will be called to get the next focusable element. If this function
126
+ * returns null, we will try to determine the next direction ourselves. Use the
127
+ * `bindKeys` option to customize which keys are listened to.
128
+ *
129
+ * The function can accept a Direction, indicating the direction focus should move,
130
+ * the HTMLElement that was previously focused, and lastly the `KeyboardEvent` object
131
+ * created by the original `"keydown"` event.
132
+ */
133
+ getNextFocusable?: (direction: Direction, from: Element | undefined, event: KeyboardEvent) => HTMLElement | undefined
134
+
135
+ /**
136
+ * Called to decide if a focusable element is allowed to participate in the arrow
137
+ * key focus behavior.
138
+ *
139
+ * By default, all focusable elements within the given container will participate
140
+ * in the arrow key focus behavior. If you need to withhold some elements from
141
+ * participation, implement this callback to return false for those elements.
142
+ */
143
+ focusableElementFilter?: (element: HTMLElement) => boolean
144
+
145
+ /**
146
+ * Bit flags that identify keys that will be bound to. Each available key either
147
+ * moves focus to the "next" element or the "previous" element, so it is best
148
+ * to only bind the keys that make sense to move focus in your UI. Use the `FocusKeys`
149
+ * object to discover supported keys.
150
+ *
151
+ * Use the bitwise "OR" operator (`|`) to combine key types. For example,
152
+ * `FocusKeys.WASD | FocusKeys.HJKL` represents all of W, A, S, D, H, J, K, and L.
153
+ *
154
+ * A note on FocusKeys.PageUpDown: This behavior does not support paging, so by default
155
+ * using these keys will result in the same behavior as Home and End. To override this
156
+ * behavior, implement `getNextFocusable`.
157
+ *
158
+ * The default for this setting is `FocusKeys.ArrowVertical | FocusKeys.HomeAndEnd`, unless
159
+ * `getNextFocusable` is provided, in which case `FocusKeys.ArrowAll | FocusKeys.HomeAndEnd`
160
+ * is used as the default.
161
+ */
162
+ bindKeys?: FocusKeys
163
+
164
+ /**
165
+ * If provided, this signal can be used to disable the behavior and remove any
166
+ * event listeners.
167
+ */
168
+ abortSignal?: AbortSignal
169
+
170
+ /**
171
+ * If `activeDescendantControl` is supplied, do not move focus or alter `tabindex` on
172
+ * any element. Instead, manage `aria-activedescendant` according to the ARIA best
173
+ * practices guidelines.
174
+ * @see https://www.w3.org/TR/wai-aria-practices-1.1/#kbd_focus_activedescendant
175
+ *
176
+ * The given `activeDescendantControl` will be given an `aria-controls` attribute that
177
+ * references the ID of the `container`. Additionally, it will be given an
178
+ * `aria-activedescendant` attribute that references the ID of the currently-active
179
+ * descendant.
180
+ *
181
+ * This element will retain DOM focus as arrow keys are pressed.
182
+ */
183
+ activeDescendantControl?: HTMLElement
184
+
185
+ /**
186
+ * Called each time the active descendant changes. Note that either of the parameters
187
+ * may be undefined, e.g. when an element in the container first becomes active, or
188
+ * when the controlling element becomes unfocused.
189
+ */
190
+ onActiveDescendantChanged?: (
191
+ newActiveDescendant: HTMLElement | undefined,
192
+ previousActiveDescendant: HTMLElement | undefined,
193
+ directlyActivated: boolean
194
+ ) => void
195
+
196
+ /**
197
+ * This option allows customization of the behavior that determines which of the
198
+ * focusable elements should be focused when focus enters the container via the Tab key.
199
+ *
200
+ * When set to "first", whenever focus enters the container via Tab, we will focus the
201
+ * first focusable element. When set to "previous", the most recently focused element
202
+ * will be focused (fallback to first if there was no previous).
203
+ *
204
+ * The "closest" strategy works like "first", except either the first or the last element
205
+ * of the container will be focused, depending on the direction from which focus comes.
206
+ *
207
+ * If a function is provided, this function should return the HTMLElement intended
208
+ * to receive focus. This is useful if you want to focus the currently "selected"
209
+ * item or element.
210
+ *
211
+ * Default: "previous"
212
+ *
213
+ * For more information, @see https://www.w3.org/TR/wai-aria-practices-1.1/#kbd_general_within
214
+ */
215
+ focusInStrategy?: 'first' | 'closest' | 'previous' | ((previousFocusedElement: Element) => HTMLElement | undefined)
216
+ }
217
+
218
+ function getDirection(keyboardEvent: KeyboardEvent) {
219
+ const direction = KEY_TO_DIRECTION[keyboardEvent.key as keyof typeof KEY_TO_DIRECTION]
220
+ if (keyboardEvent.key === 'Tab' && keyboardEvent.shiftKey) {
221
+ return 'previous'
222
+ }
223
+ const isMac = isMacOS()
224
+ if ((isMac && keyboardEvent.metaKey) || (!isMac && keyboardEvent.ctrlKey)) {
225
+ if (keyboardEvent.key === 'ArrowLeft' || keyboardEvent.key === 'ArrowUp') {
226
+ return 'start'
227
+ } else if (keyboardEvent.key === 'ArrowRight' || keyboardEvent.key === 'ArrowDown') {
228
+ return 'end'
229
+ }
230
+ }
231
+ return direction
232
+ }
233
+
234
+ /**
235
+ * There are some situations where we do not want various keys to affect focus. This function
236
+ * checks for those situations.
237
+ * 1. Home and End should not move focus when a text input or textarea is active
238
+ * 2. Keys that would normally type characters into an input or navigate a select element should be ignored
239
+ * 3. The down arrow sometimes should not move focus when a select is active since that sometimes invokes the dropdown
240
+ * 4. Page Up and Page Down within a textarea should not have any effect
241
+ * 5. When in a text input or textarea, left should only move focus if the cursor is at the beginning of the input
242
+ * 6. When in a text input or textarea, right should only move focus if the cursor is at the end of the input
243
+ * 7. When in a textarea, up and down should only move focus if cursor is at the beginning or end, respectively.
244
+ * @param keyboardEvent
245
+ * @param activeElement
246
+ */
247
+ function shouldIgnoreFocusHandling(keyboardEvent: KeyboardEvent, activeElement: Element | null) {
248
+ const key = keyboardEvent.key
249
+
250
+ // Get the number of characters in `key`, accounting for double-wide UTF-16 chars. If keyLength
251
+ // is 1, we can assume it's a "printable" character. Otherwise it's likely a control character.
252
+ // One exception is the Tab key, which is technically printable, but browsers generally assign
253
+ // its function to move focus rather than type a <TAB> character.
254
+ const keyLength = [...key].length
255
+
256
+ const isTextInput =
257
+ (activeElement instanceof HTMLInputElement && activeElement.type === 'text') ||
258
+ activeElement instanceof HTMLTextAreaElement
259
+
260
+ // If we would normally type a character into an input, ignore
261
+ // Also, Home and End keys should never affect focus when in a text input
262
+ if (isTextInput && (keyLength === 1 || key === 'Home' || key === 'End')) {
263
+ return true
264
+ }
265
+
266
+ // Some situations we want to ignore with <select> elements
267
+ if (activeElement instanceof HTMLSelectElement) {
268
+ // Regular typeable characters change the selection, so ignore those
269
+ if (keyLength === 1) {
270
+ return true
271
+ }
272
+ // On macOS, bare ArrowDown opens the select, so ignore that
273
+ if (key === 'ArrowDown' && isMacOS() && !keyboardEvent.metaKey) {
274
+ return true
275
+ }
276
+ // On other platforms, Alt+ArrowDown opens the select, so ignore that
277
+ if (key === 'ArrowDown' && !isMacOS() && keyboardEvent.altKey) {
278
+ return true
279
+ }
280
+ }
281
+
282
+ // Ignore page up and page down for textareas
283
+ if (activeElement instanceof HTMLTextAreaElement && (key === 'PageUp' || key === 'PageDown')) {
284
+ return true
285
+ }
286
+
287
+ if (isTextInput) {
288
+ const textInput = activeElement as HTMLInputElement | HTMLTextAreaElement
289
+ const cursorAtStart = textInput.selectionStart === 0 && textInput.selectionEnd === 0
290
+ const cursorAtEnd =
291
+ textInput.selectionStart === textInput.value.length && textInput.selectionEnd === textInput.value.length
292
+
293
+ // When in a text area or text input, only move focus left/right if at beginning/end of the field
294
+ if (key === 'ArrowLeft' && !cursorAtStart) {
295
+ return true
296
+ }
297
+ if (key === 'ArrowRight' && !cursorAtEnd) {
298
+ return true
299
+ }
300
+
301
+ // When in a text area, only move focus up/down if at beginning/end of the field
302
+ if (textInput instanceof HTMLTextAreaElement) {
303
+ if (key === 'ArrowUp' && !cursorAtStart) {
304
+ return true
305
+ }
306
+ if (key === 'ArrowDown' && !cursorAtEnd) {
307
+ return true
308
+ }
309
+ }
310
+ }
311
+
312
+ return false
313
+ }
314
+
315
+ export const isActiveDescendantAttribute = 'data-is-active-descendant'
316
+ /**
317
+ * A value of activated-directly for data-is-active-descendant indicates the descendant was activated
318
+ * by a manual user interaction with intent to move active descendant. This usually translates to the
319
+ * user pressing one of the bound keys (up/down arrow, etc) to move through the focus zone. This is
320
+ * intended to be roughly equivalent to the :focus-visible pseudo-class
321
+ **/
322
+ export const activeDescendantActivatedDirectly = 'activated-directly'
323
+ /**
324
+ * A value of activated-indirectly for data-is-active-descendant indicates the descendant was activated
325
+ * implicitly, and not by a direct key press. This includes focus zone being created from scratch, focusable
326
+ * elements being added/removed, and mouseover events. This is intended to be roughly equivalent
327
+ * to :focus:not(:focus-visible)
328
+ **/
329
+ export const activeDescendantActivatedIndirectly = 'activated-indirectly'
330
+ export const hasActiveDescendantAttribute = 'data-has-active-descendant'
331
+
332
+ /**
333
+ * Sets up the arrow key focus behavior for all focusable elements in the given `container`.
334
+ * @param container
335
+ * @param settings
336
+ * @returns
337
+ */
338
+ export function focusZone(container: HTMLElement, settings?: FocusZoneSettings): AbortController {
339
+ const focusableElements: HTMLElement[] = []
340
+ const savedTabIndex = new WeakMap<HTMLElement, string | null>()
341
+ const bindKeys =
342
+ settings?.bindKeys ??
343
+ (settings?.getNextFocusable ? FocusKeys.ArrowAll : FocusKeys.ArrowVertical) | FocusKeys.HomeAndEnd
344
+ const focusOutBehavior = settings?.focusOutBehavior ?? 'stop'
345
+ const focusInStrategy = settings?.focusInStrategy ?? 'previous'
346
+ const activeDescendantControl = settings?.activeDescendantControl
347
+ const activeDescendantCallback = settings?.onActiveDescendantChanged
348
+ let currentFocusedElement: HTMLElement | undefined
349
+
350
+ function getFirstFocusableElement() {
351
+ return focusableElements[0] as HTMLElement | undefined
352
+ }
353
+
354
+ function isActiveDescendantInputFocused() {
355
+ return document.activeElement === activeDescendantControl
356
+ }
357
+
358
+ function updateFocusedElement(to?: HTMLElement, directlyActivated = false) {
359
+ const from = currentFocusedElement
360
+ currentFocusedElement = to
361
+
362
+ if (activeDescendantControl) {
363
+ if (to && isActiveDescendantInputFocused()) {
364
+ setActiveDescendant(from, to, directlyActivated)
365
+ } else {
366
+ clearActiveDescendant()
367
+ }
368
+
369
+ return
370
+ }
371
+
372
+ if (from && from !== to && savedTabIndex.has(from)) {
373
+ from.setAttribute('tabindex', '-1')
374
+ }
375
+
376
+ to?.setAttribute('tabindex', '0')
377
+ }
378
+
379
+ function setActiveDescendant(from: HTMLElement | undefined, to: HTMLElement, directlyActivated = false) {
380
+ if (!to.id) {
381
+ to.setAttribute('id', uniqueId())
382
+ }
383
+
384
+ if (from && from !== to) {
385
+ from.removeAttribute(isActiveDescendantAttribute)
386
+ }
387
+
388
+ if (
389
+ !activeDescendantControl ||
390
+ (!directlyActivated && activeDescendantControl.getAttribute('aria-activedescendant') === to.id)
391
+ ) {
392
+ // prevent active descendant callback from being called repeatedly if the same element is activated (e.g. via mousemove)
393
+ return
394
+ }
395
+
396
+ activeDescendantControl.setAttribute('aria-activedescendant', to.id)
397
+ container.setAttribute(hasActiveDescendantAttribute, to.id)
398
+ to.setAttribute(
399
+ isActiveDescendantAttribute,
400
+ directlyActivated ? activeDescendantActivatedDirectly : activeDescendantActivatedIndirectly
401
+ )
402
+ activeDescendantCallback?.(to, from, directlyActivated)
403
+ }
404
+
405
+ function clearActiveDescendant(previouslyActiveElement = currentFocusedElement) {
406
+ if (focusInStrategy === 'first') {
407
+ currentFocusedElement = undefined
408
+ }
409
+
410
+ activeDescendantControl?.removeAttribute('aria-activedescendant')
411
+ container.removeAttribute(hasActiveDescendantAttribute)
412
+ previouslyActiveElement?.removeAttribute(isActiveDescendantAttribute)
413
+ activeDescendantCallback?.(undefined, previouslyActiveElement, false)
414
+ }
415
+
416
+ function beginFocusManagement(...elements: HTMLElement[]) {
417
+ const filteredElements = elements.filter(e => settings?.focusableElementFilter?.(e) ?? true)
418
+ if (filteredElements.length === 0) {
419
+ return
420
+ }
421
+ // Insert all elements atomically. Assume that all passed elements are well-ordered.
422
+ const insertIndex = focusableElements.findIndex(
423
+ e => (e.compareDocumentPosition(filteredElements[0]) & Node.DOCUMENT_POSITION_PRECEDING) > 0
424
+ )
425
+ focusableElements.splice(insertIndex === -1 ? focusableElements.length : insertIndex, 0, ...filteredElements)
426
+ for (const element of filteredElements) {
427
+ // Set tabindex="-1" on all tabbable elements, but save the original
428
+ // value in case we need to disable the behavior
429
+ if (!savedTabIndex.has(element)) {
430
+ savedTabIndex.set(element, element.getAttribute('tabindex'))
431
+ }
432
+ element.setAttribute('tabindex', '-1')
433
+ }
434
+
435
+ if (!currentFocusedElement) {
436
+ updateFocusedElement(getFirstFocusableElement())
437
+ }
438
+ }
439
+
440
+ function endFocusManagement(...elements: HTMLElement[]) {
441
+ for (const element of elements) {
442
+ const focusableElementIndex = focusableElements.indexOf(element)
443
+ if (focusableElementIndex >= 0) {
444
+ focusableElements.splice(focusableElementIndex, 1)
445
+ }
446
+ const savedIndex = savedTabIndex.get(element)
447
+ if (savedIndex !== undefined) {
448
+ if (savedIndex === null) {
449
+ element.removeAttribute('tabindex')
450
+ } else {
451
+ element.setAttribute('tabindex', savedIndex)
452
+ }
453
+ savedTabIndex.delete(element)
454
+ }
455
+
456
+ // If removing the last-focused element, move focus to the first element in the list.
457
+ if (element === currentFocusedElement) {
458
+ const nextElementToFocus = getFirstFocusableElement()
459
+ updateFocusedElement(nextElementToFocus)
460
+ }
461
+ }
462
+ }
463
+
464
+ // Take all tabbable elements within container under management
465
+ beginFocusManagement(...iterateFocusableElements(container))
466
+
467
+ // Open the first tabbable element for tabbing
468
+ updateFocusedElement(getFirstFocusableElement())
469
+
470
+ // If the DOM structure of the container changes, make sure we keep our state up-to-date
471
+ // with respect to the focusable elements cache and its order
472
+ const observer = new MutationObserver(mutations => {
473
+ // Perform all removals first, in case element order has simply changed
474
+ for (const mutation of mutations) {
475
+ for (const removedNode of mutation.removedNodes) {
476
+ if (removedNode instanceof HTMLElement) {
477
+ endFocusManagement(...iterateFocusableElements(removedNode))
478
+ }
479
+ }
480
+ }
481
+ for (const mutation of mutations) {
482
+ for (const addedNode of mutation.addedNodes) {
483
+ if (addedNode instanceof HTMLElement) {
484
+ beginFocusManagement(...iterateFocusableElements(addedNode))
485
+ }
486
+ }
487
+ }
488
+ })
489
+
490
+ observer.observe(container, {
491
+ subtree: true,
492
+ childList: true
493
+ })
494
+
495
+ const controller = new AbortController()
496
+ const signal = settings?.abortSignal ?? controller.signal
497
+
498
+ signal.addEventListener('abort', () => {
499
+ // Clean up any modifications
500
+ endFocusManagement(...focusableElements)
501
+ })
502
+
503
+ let elementIndexFocusedByClick: number | undefined = undefined
504
+ container.addEventListener(
505
+ 'mousedown',
506
+ event => {
507
+ // Since focusin is only called when focus changes, we need to make sure the clicked
508
+ // element isn't already focused.
509
+ if (event.target instanceof HTMLElement && event.target !== document.activeElement) {
510
+ elementIndexFocusedByClick = focusableElements.indexOf(event.target)
511
+ }
512
+ },
513
+ {signal}
514
+ )
515
+
516
+ if (activeDescendantControl) {
517
+ container.addEventListener('focusin', event => {
518
+ if (event.target instanceof HTMLElement && focusableElements.includes(event.target)) {
519
+ // Move focus to the activeDescendantControl if one of the descendants is focused
520
+ activeDescendantControl.focus()
521
+ updateFocusedElement(event.target)
522
+ }
523
+ })
524
+ container.addEventListener(
525
+ 'mousemove',
526
+ ({target}) => {
527
+ if (!(target instanceof Node)) {
528
+ return
529
+ }
530
+
531
+ const focusableElement = focusableElements.find(element => element.contains(target))
532
+
533
+ if (focusableElement) {
534
+ updateFocusedElement(focusableElement)
535
+ }
536
+ },
537
+ {signal, capture: true}
538
+ )
539
+
540
+ // Listeners specifically on the controlling element
541
+ activeDescendantControl.addEventListener('focusin', () => {
542
+ // Focus moved into the active descendant input. Activate current or first descendant.
543
+ if (!currentFocusedElement) {
544
+ updateFocusedElement(getFirstFocusableElement())
545
+ } else {
546
+ setActiveDescendant(undefined, currentFocusedElement)
547
+ }
548
+ })
549
+ activeDescendantControl.addEventListener('focusout', () => {
550
+ clearActiveDescendant()
551
+ })
552
+ } else {
553
+ // This is called whenever focus enters an element in the container
554
+ container.addEventListener(
555
+ 'focusin',
556
+ event => {
557
+ if (event.target instanceof HTMLElement) {
558
+ // If a click initiated the focus movement, we always want to set our internal state
559
+ // to reflect the clicked element as the currently focused one.
560
+ if (elementIndexFocusedByClick !== undefined) {
561
+ if (elementIndexFocusedByClick >= 0) {
562
+ if (focusableElements[elementIndexFocusedByClick] !== currentFocusedElement) {
563
+ updateFocusedElement(focusableElements[elementIndexFocusedByClick])
564
+ }
565
+ }
566
+ elementIndexFocusedByClick = undefined
567
+ } else {
568
+ // Set tab indexes and internal state based on the focus handling strategy
569
+ if (focusInStrategy === 'previous') {
570
+ updateFocusedElement(event.target)
571
+ } else if (focusInStrategy === 'closest' || focusInStrategy === 'first') {
572
+ if (event.relatedTarget instanceof Element && !container.contains(event.relatedTarget)) {
573
+ // Regardless of the previously focused element, if we're coming from outside the
574
+ // container, put focus onto the first encountered element (from above, it's The
575
+ // first element of the container; from below, it's the last). If the
576
+ // focusInStrategy is set to "first", lastKeyboardFocusDirection will always
577
+ // be undefined.
578
+ const targetElementIndex = lastKeyboardFocusDirection === 'previous' ? focusableElements.length - 1 : 0
579
+ const targetElement = focusableElements[targetElementIndex] as HTMLElement | undefined
580
+ targetElement?.focus()
581
+ return
582
+ } else {
583
+ updateFocusedElement(event.target)
584
+ }
585
+ } else if (typeof focusInStrategy === 'function') {
586
+ if (event.relatedTarget instanceof Element && !container.contains(event.relatedTarget)) {
587
+ const elementToFocus = focusInStrategy(event.relatedTarget)
588
+ const requestedFocusElementIndex = elementToFocus ? focusableElements.indexOf(elementToFocus) : -1
589
+ if (requestedFocusElementIndex >= 0 && elementToFocus instanceof HTMLElement) {
590
+ // Since we are calling focus() this handler will run again synchronously. Therefore,
591
+ // we don't want to let this invocation finish since it will clobber the value of
592
+ // currentFocusedElement.
593
+ elementToFocus.focus()
594
+ return
595
+ } else {
596
+ // eslint-disable-next-line no-console
597
+ console.warn('Element requested is not a known focusable element.')
598
+ }
599
+ } else {
600
+ updateFocusedElement(event.target)
601
+ }
602
+ }
603
+ }
604
+ }
605
+ lastKeyboardFocusDirection = undefined
606
+ },
607
+ {signal}
608
+ )
609
+ }
610
+
611
+ const keyboardEventRecipient = activeDescendantControl ?? container
612
+
613
+ // If the strategy is "closest", we need to capture the direction that the user
614
+ // is trying to move focus before our focusin handler is executed.
615
+ let lastKeyboardFocusDirection: Direction | undefined = undefined
616
+ if (focusInStrategy === 'closest') {
617
+ document.addEventListener(
618
+ 'keydown',
619
+ event => {
620
+ if (event.key === 'Tab') {
621
+ lastKeyboardFocusDirection = getDirection(event)
622
+ }
623
+ },
624
+ {signal, capture: true}
625
+ )
626
+ }
627
+
628
+ function getCurrentFocusedIndex() {
629
+ if (!currentFocusedElement) {
630
+ return 0
631
+ }
632
+
633
+ const focusedIndex = focusableElements.indexOf(currentFocusedElement)
634
+ const fallbackIndex = currentFocusedElement === container ? -1 : 0
635
+
636
+ return focusedIndex !== -1 ? focusedIndex : fallbackIndex
637
+ }
638
+
639
+ // "keydown" is the event that triggers DOM focus change, so that is what we use here
640
+ keyboardEventRecipient.addEventListener(
641
+ 'keydown',
642
+ event => {
643
+ if (event.key in KEY_TO_DIRECTION) {
644
+ const keyBit = KEY_TO_BIT[event.key as keyof typeof KEY_TO_BIT]
645
+ // Check if the pressed key (keyBit) is one that is being used for focus (bindKeys)
646
+ if (
647
+ !event.defaultPrevented &&
648
+ (keyBit & bindKeys) > 0 &&
649
+ !shouldIgnoreFocusHandling(event, document.activeElement)
650
+ ) {
651
+ // Moving forward or backward?
652
+ const direction = getDirection(event)
653
+
654
+ let nextElementToFocus: HTMLElement | undefined = undefined
655
+
656
+ // If there is a custom function that retrieves the next focusable element, try calling that first.
657
+ if (settings?.getNextFocusable) {
658
+ nextElementToFocus = settings.getNextFocusable(direction, document.activeElement ?? undefined, event)
659
+ }
660
+ if (!nextElementToFocus) {
661
+ const lastFocusedIndex = getCurrentFocusedIndex()
662
+ let nextFocusedIndex = lastFocusedIndex
663
+ if (direction === 'previous') {
664
+ nextFocusedIndex -= 1
665
+ } else if (direction === 'start') {
666
+ nextFocusedIndex = 0
667
+ } else if (direction === 'next') {
668
+ nextFocusedIndex += 1
669
+ } else {
670
+ // end
671
+ nextFocusedIndex = focusableElements.length - 1
672
+ }
673
+
674
+ if (nextFocusedIndex < 0) {
675
+ // Tab should never cause focus to wrap. Use focusTrap for that behavior.
676
+ if (focusOutBehavior === 'wrap' && event.key !== 'Tab') {
677
+ nextFocusedIndex = focusableElements.length - 1
678
+ } else {
679
+ nextFocusedIndex = 0
680
+ }
681
+ }
682
+ if (nextFocusedIndex >= focusableElements.length) {
683
+ if (focusOutBehavior === 'wrap' && event.key !== 'Tab') {
684
+ nextFocusedIndex = 0
685
+ } else {
686
+ nextFocusedIndex = focusableElements.length - 1
687
+ }
688
+ }
689
+ if (lastFocusedIndex !== nextFocusedIndex) {
690
+ nextElementToFocus = focusableElements[nextFocusedIndex]
691
+ }
692
+ }
693
+
694
+ if (activeDescendantControl) {
695
+ updateFocusedElement(nextElementToFocus || currentFocusedElement, true)
696
+ } else if (nextElementToFocus) {
697
+ lastKeyboardFocusDirection = direction
698
+
699
+ // updateFocusedElement will be called implicitly when focus moves, as long as the event isn't prevented somehow
700
+ nextElementToFocus.focus()
701
+ }
702
+ // Tab should always allow escaping from this container, so only
703
+ // preventDefault if tab key press already resulted in a focus movement
704
+ if (event.key !== 'Tab' || nextElementToFocus) {
705
+ event.preventDefault()
706
+ }
707
+ }
708
+ }
709
+ },
710
+ {signal}
711
+ )
712
+ return controller
713
+ }