@primer/components 31.0.1 → 31.0.2-rc.1e80de40
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.
- package/.changeset/README.md +8 -0
- package/.changeset/config.json +10 -0
- package/.devcontainer/devcontainer.json +8 -0
- package/.eslintrc.json +137 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
- package/.github/ISSUE_TEMPLATE/new_component_proposal_template.md +41 -0
- package/.github/dependabot.yml +18 -0
- package/.github/pull_request_template.md +18 -0
- package/.github/workflows/check_for_changeset.yml +25 -0
- package/.github/workflows/ci.yml +31 -0
- package/.github/workflows/deploy_preview.yml +47 -0
- package/.github/workflows/deploy_production.yml +70 -0
- package/.github/workflows/release.yml +35 -0
- package/.github/workflows/release_canary.yml +70 -0
- package/.github/workflows/release_candidate.yml +60 -0
- package/.github/workflows/size.yml +13 -0
- package/.github/workflows/stale.yml +26 -0
- package/.gitignore +10 -0
- package/.npmrc +4 -0
- package/.nvmrc +1 -0
- package/.storybook/main.js +11 -0
- package/.storybook/preview.js +113 -0
- package/.vscode/launch.json +21 -0
- package/.vscode/settings.json +13 -0
- package/@types/@styled-system/index.d.ts +0 -0
- package/@types/@styled-system/prop-types/index.d.ts +1 -0
- package/@types/@styled-system/props/index.d.ts +1 -0
- package/@types/jest-styled-components/index.d.ts +1 -0
- package/CHANGELOG.md +6 -0
- package/CODEOWNERS +2 -0
- package/babel-defines.js +13 -0
- package/babel.config.js +39 -0
- package/contributor-docs/CODE_OF_CONDUCT.md +76 -0
- package/contributor-docs/CONTRIBUTING.md +274 -0
- package/contributor-docs/adrs/adr-001-typescript.md +23 -0
- package/contributor-docs/adrs/adr-002-behavior-isolation.md +108 -0
- package/contributor-docs/adrs/adr-003-prop-norms.md +72 -0
- package/contributor-docs/behaviors.md +132 -0
- package/contributor-docs/component-contents-api-patterns.md +316 -0
- package/contributor-docs/principles.md +39 -0
- package/dist/browser.esm.js +35 -32
- package/dist/browser.esm.js.map +1 -1
- package/dist/browser.umd.js +29 -26
- package/dist/browser.umd.js.map +1 -1
- package/docs/.eslintrc +0 -0
- package/docs/.gitignore +91 -0
- package/docs/components/PropsList.js +5 -0
- package/docs/components/State.js +9 -0
- package/docs/components/constants.js +34 -0
- package/docs/components/index.js +2 -0
- package/docs/content/ActionList.mdx +99 -0
- package/docs/content/ActionMenu.mdx +80 -0
- package/docs/content/AnchoredOverlay.mdx +37 -0
- package/docs/content/Autocomplete.mdx +657 -0
- package/docs/content/Avatar.mdx +33 -0
- package/docs/content/AvatarStack.mdx +37 -0
- package/docs/content/BorderBox.md +46 -0
- package/docs/content/Box.md +74 -0
- package/docs/content/BranchName.md +18 -0
- package/docs/content/Breadcrumbs.md +52 -0
- package/docs/content/Buttons.md +56 -0
- package/docs/content/CircleBadge.md +45 -0
- package/docs/content/CircleOcticon.md +18 -0
- package/docs/content/CounterLabel.md +32 -0
- package/docs/content/Details.md +105 -0
- package/docs/content/Dialog.md +108 -0
- package/docs/content/Dialog2.mdx +179 -0
- package/docs/content/Dropdown.md +72 -0
- package/docs/content/DropdownMenu.mdx +49 -0
- package/docs/content/FilterList.md +44 -0
- package/docs/content/FilteredSearch.md +39 -0
- package/docs/content/Flash.md +44 -0
- package/docs/content/Flex.md +58 -0
- package/docs/content/FormGroup.md +46 -0
- package/docs/content/Grid.md +59 -0
- package/docs/content/Header.md +79 -0
- package/docs/content/Heading.md +22 -0
- package/docs/content/Label.md +42 -0
- package/docs/content/LabelGroup.md +31 -0
- package/docs/content/Link.md +37 -0
- package/docs/content/Overlay.mdx +94 -0
- package/docs/content/Pagehead.md +27 -0
- package/docs/content/Pagination.md +187 -0
- package/docs/content/PointerBox.md +81 -0
- package/docs/content/Popover.md +137 -0
- package/docs/content/Portal.mdx +78 -0
- package/docs/content/Position.md +100 -0
- package/docs/content/ProgressBar.mdx +29 -0
- package/docs/content/SelectMenu.md +435 -0
- package/docs/content/SelectPanel.mdx +67 -0
- package/docs/content/SideNav.md +179 -0
- package/docs/content/Spinner.mdx +32 -0
- package/docs/content/StateLabel.md +35 -0
- package/docs/content/StyledOcticon.md +36 -0
- package/docs/content/SubNav.md +102 -0
- package/docs/content/TabNav.md +50 -0
- package/docs/content/Text.md +31 -0
- package/docs/content/TextInput.md +34 -0
- package/docs/content/TextInputTokens.mdx +89 -0
- package/docs/content/TextInputWithTokens.mdx +97 -0
- package/docs/content/Timeline.md +138 -0
- package/docs/content/Token.mdx +381 -0
- package/docs/content/Tooltip.md +41 -0
- package/docs/content/Truncate.md +64 -0
- package/docs/content/UnderlineNav.md +53 -0
- package/docs/content/anchoredPosition.mdx +163 -0
- package/docs/content/core-concepts.md +70 -0
- package/docs/content/focusTrap.mdx +103 -0
- package/docs/content/focusZone.mdx +145 -0
- package/docs/content/getting-started.md +138 -0
- package/docs/content/index.md +33 -0
- package/docs/content/linting.md +35 -0
- package/docs/content/overriding-styles.mdx +82 -0
- package/docs/content/philosophy.md +23 -0
- package/docs/content/primer-theme.md +89 -0
- package/docs/content/ssr.mdx +43 -0
- package/docs/content/system-props.mdx +37 -0
- package/docs/content/theme-reference.md +16 -0
- package/docs/content/theming.md +249 -0
- package/docs/content/useOnEscapePress.mdx +56 -0
- package/docs/content/useOnOutsideClick.mdx +57 -0
- package/docs/content/useOpenAndCloseFocus.mdx +49 -0
- package/docs/content/useOverlay.mdx +62 -0
- package/docs/content/useSafeTimeout.mdx +32 -0
- package/docs/gatsby-config.js +30 -0
- package/docs/gatsby-node.js +101 -0
- package/docs/package-lock.json +20756 -0
- package/docs/package.json +36 -0
- package/docs/src/@primer/gatsby-theme-doctocat/components/hero.js +23 -0
- package/docs/src/@primer/gatsby-theme-doctocat/components/live-preview-wrapper.js +41 -0
- package/docs/src/@primer/gatsby-theme-doctocat/live-code-scope.js +56 -0
- package/docs/src/@primer/gatsby-theme-doctocat/nav.yml +133 -0
- package/docs/src/@primer/gatsby-theme-doctocat/primer-components-hero.svg +1411 -0
- package/docs/src/props.js +77 -0
- package/jest.config.js +13 -0
- package/lib/TextInputWithTokens.js +17 -10
- package/lib/Token/Token.js +13 -2
- package/lib/Token/TokenBase.js +0 -4
- package/lib/Token/_RemoveTokenButton.js +15 -2
- package/lib/__tests__/ActionList.test.d.ts +1 -0
- package/lib/__tests__/ActionList.test.js +69 -0
- package/lib/__tests__/ActionList.types.test.d.ts +6 -0
- package/lib/__tests__/ActionList.types.test.js +69 -0
- package/lib/__tests__/ActionMenu.test.d.ts +1 -0
- package/lib/__tests__/ActionMenu.test.js +151 -0
- package/lib/__tests__/AnchoredOverlay.test.d.ts +1 -0
- package/lib/__tests__/AnchoredOverlay.test.js +160 -0
- package/lib/__tests__/Autocomplete.test.d.ts +1 -0
- package/lib/__tests__/Autocomplete.test.js +528 -0
- package/lib/__tests__/Avatar.test.d.ts +1 -0
- package/lib/__tests__/Avatar.test.js +67 -0
- package/lib/__tests__/AvatarStack.test.d.ts +1 -0
- package/lib/__tests__/AvatarStack.test.js +71 -0
- package/lib/__tests__/BorderBox.test.d.ts +1 -0
- package/lib/__tests__/BorderBox.test.js +58 -0
- package/lib/__tests__/Box.test.d.ts +1 -0
- package/lib/__tests__/Box.test.js +78 -0
- package/lib/__tests__/BranchName.test.d.ts +1 -0
- package/lib/__tests__/BranchName.test.js +36 -0
- package/lib/__tests__/Breadcrumbs.test.d.ts +1 -0
- package/lib/__tests__/Breadcrumbs.test.js +37 -0
- package/lib/__tests__/BreadcrumbsItem.test.d.ts +1 -0
- package/lib/__tests__/BreadcrumbsItem.test.js +49 -0
- package/lib/__tests__/Button.test.d.ts +1 -0
- package/lib/__tests__/Button.test.js +143 -0
- package/lib/__tests__/Caret.test.d.ts +1 -0
- package/lib/__tests__/Caret.test.js +52 -0
- package/lib/__tests__/CircleBadge.test.d.ts +1 -0
- package/lib/__tests__/CircleBadge.test.js +83 -0
- package/lib/__tests__/CircleOcticon.test.d.ts +1 -0
- package/lib/__tests__/CircleOcticon.test.js +71 -0
- package/lib/__tests__/ConfirmationDialog.test.d.ts +1 -0
- package/lib/__tests__/ConfirmationDialog.test.js +134 -0
- package/lib/__tests__/CounterLabel.test.d.ts +1 -0
- package/lib/__tests__/CounterLabel.test.js +58 -0
- package/lib/__tests__/Details.test.d.ts +1 -0
- package/lib/__tests__/Details.test.js +117 -0
- package/lib/__tests__/Dialog.test.d.ts +1 -0
- package/lib/__tests__/Dialog.test.js +184 -0
- package/lib/__tests__/Dropdown.test.d.ts +1 -0
- package/lib/__tests__/Dropdown.test.js +63 -0
- package/lib/__tests__/DropdownMenu.test.d.ts +1 -0
- package/lib/__tests__/DropdownMenu.test.js +150 -0
- package/lib/__tests__/FilterList.test.d.ts +1 -0
- package/lib/__tests__/FilterList.test.js +36 -0
- package/lib/__tests__/FilterListItem.test.d.ts +1 -0
- package/lib/__tests__/FilterListItem.test.js +46 -0
- package/lib/__tests__/FilteredSearch.test.d.ts +1 -0
- package/lib/__tests__/FilteredSearch.test.js +36 -0
- package/lib/__tests__/Flash.test.d.ts +1 -0
- package/lib/__tests__/Flash.test.js +62 -0
- package/lib/__tests__/Flex.test.d.ts +1 -0
- package/lib/__tests__/Flex.test.js +74 -0
- package/lib/__tests__/FormGroup.test.d.ts +1 -0
- package/lib/__tests__/FormGroup.test.js +54 -0
- package/lib/__tests__/Grid.test.d.ts +1 -0
- package/lib/__tests__/Grid.test.js +104 -0
- package/lib/__tests__/Header.test.d.ts +1 -0
- package/lib/__tests__/Header.test.js +58 -0
- package/lib/__tests__/Heading.test.d.ts +1 -0
- package/lib/__tests__/Heading.test.js +109 -0
- package/lib/__tests__/Label.test.d.ts +1 -0
- package/lib/__tests__/Label.test.js +46 -0
- package/lib/__tests__/LabelGroup.test.d.ts +1 -0
- package/lib/__tests__/LabelGroup.test.js +38 -0
- package/lib/__tests__/Link.test.d.ts +1 -0
- package/lib/__tests__/Link.test.js +70 -0
- package/lib/__tests__/Merge.types.test.d.ts +30 -0
- package/lib/__tests__/Merge.types.test.js +27 -0
- package/lib/__tests__/Overlay.test.d.ts +1 -0
- package/lib/__tests__/Overlay.test.js +145 -0
- package/lib/__tests__/Pagehead.test.d.ts +1 -0
- package/lib/__tests__/Pagehead.test.js +37 -0
- package/lib/__tests__/Pagination/Pagination.test.d.ts +1 -0
- package/lib/__tests__/Pagination/Pagination.test.js +47 -0
- package/lib/__tests__/Pagination/PaginationModel.test.d.ts +1 -0
- package/lib/__tests__/Pagination/PaginationModel.test.js +186 -0
- package/lib/__tests__/PointerBox.test.d.ts +1 -0
- package/lib/__tests__/PointerBox.test.js +46 -0
- package/lib/__tests__/Popover.test.d.ts +1 -0
- package/lib/__tests__/Popover.test.js +66 -0
- package/lib/__tests__/Portal.test.d.ts +1 -0
- package/lib/__tests__/Portal.test.js +124 -0
- package/lib/__tests__/Position.test.d.ts +1 -0
- package/lib/__tests__/Position.test.js +143 -0
- package/lib/__tests__/ProgressBar.test.d.ts +1 -0
- package/lib/__tests__/ProgressBar.test.js +68 -0
- package/lib/__tests__/SelectMenu.test.d.ts +1 -0
- package/lib/__tests__/SelectMenu.test.js +155 -0
- package/lib/__tests__/SelectPanel.test.d.ts +1 -0
- package/lib/__tests__/SelectPanel.test.js +80 -0
- package/lib/__tests__/SideNav.test.d.ts +1 -0
- package/lib/__tests__/SideNav.test.js +71 -0
- package/lib/__tests__/Spinner.test.d.ts +1 -0
- package/lib/__tests__/Spinner.test.js +53 -0
- package/lib/__tests__/StateLabel.test.d.ts +1 -0
- package/lib/__tests__/StateLabel.test.js +71 -0
- package/lib/__tests__/StyledOcticon.test.d.ts +1 -0
- package/lib/__tests__/StyledOcticon.test.js +40 -0
- package/lib/__tests__/SubNav.test.d.ts +1 -0
- package/lib/__tests__/SubNav.test.js +62 -0
- package/lib/__tests__/SubNavLink.test.d.ts +1 -0
- package/lib/__tests__/SubNavLink.test.js +49 -0
- package/lib/__tests__/TabNav.test.d.ts +1 -0
- package/lib/__tests__/TabNav.test.js +49 -0
- package/lib/__tests__/Text.test.d.ts +1 -0
- package/lib/__tests__/Text.test.js +105 -0
- package/lib/__tests__/TextInput.test.d.ts +1 -0
- package/lib/__tests__/TextInput.test.js +78 -0
- package/lib/__tests__/TextInputWithTokens.test.d.ts +1 -0
- package/lib/__tests__/TextInputWithTokens.test.js +389 -0
- package/lib/__tests__/ThemeProvider.test.d.ts +1 -0
- package/lib/__tests__/ThemeProvider.test.js +444 -0
- package/lib/__tests__/Timeline.test.d.ts +1 -0
- package/lib/__tests__/Timeline.test.js +75 -0
- package/lib/__tests__/Token.test.d.ts +1 -0
- package/lib/__tests__/Token.test.js +180 -0
- package/lib/__tests__/Tooltip.test.d.ts +1 -0
- package/lib/__tests__/Tooltip.test.js +69 -0
- package/lib/__tests__/Truncate.test.d.ts +1 -0
- package/lib/__tests__/Truncate.test.js +63 -0
- package/lib/__tests__/UnderlineNav.test.d.ts +1 -0
- package/lib/__tests__/UnderlineNav.test.js +72 -0
- package/lib/__tests__/UnderlineNavLink.test.d.ts +1 -0
- package/lib/__tests__/UnderlineNavLink.test.js +51 -0
- package/lib/__tests__/behaviors/anchoredPosition.test.d.ts +1 -0
- package/lib/__tests__/behaviors/anchoredPosition.test.js +390 -0
- package/lib/__tests__/behaviors/focusTrap.test.d.ts +1 -0
- package/lib/__tests__/behaviors/focusTrap.test.js +234 -0
- package/lib/__tests__/behaviors/focusZone.test.d.ts +1 -0
- package/lib/__tests__/behaviors/focusZone.test.js +570 -0
- package/lib/__tests__/behaviors/iterateFocusableElements.test.d.ts +1 -0
- package/lib/__tests__/behaviors/iterateFocusableElements.test.js +55 -0
- package/lib/__tests__/behaviors/scrollIntoViewingArea.test.d.ts +1 -0
- package/lib/__tests__/behaviors/scrollIntoViewingArea.test.js +226 -0
- package/lib/__tests__/filterObject.test.d.ts +1 -0
- package/lib/__tests__/filterObject.test.js +30 -0
- package/lib/__tests__/hooks/useAnchoredPosition.test.d.ts +1 -0
- package/lib/__tests__/hooks/useAnchoredPosition.test.js +54 -0
- package/lib/__tests__/hooks/useOnEscapePress.test.d.ts +1 -0
- package/lib/__tests__/hooks/useOnEscapePress.test.js +32 -0
- package/lib/__tests__/hooks/useOnOutsideClick.test.d.ts +1 -0
- package/lib/__tests__/hooks/useOnOutsideClick.test.js +87 -0
- package/lib/__tests__/hooks/useOpenAndCloseFocus.test.d.ts +1 -0
- package/lib/__tests__/hooks/useOpenAndCloseFocus.test.js +60 -0
- package/lib/__tests__/hooks/useProvidedStateOrCreate.test.d.ts +1 -0
- package/lib/__tests__/hooks/useProvidedStateOrCreate.test.js +45 -0
- package/lib/__tests__/theme.test.d.ts +1 -0
- package/lib/__tests__/theme.test.js +36 -0
- package/lib/__tests__/themeGet.test.d.ts +1 -0
- package/lib/__tests__/themeGet.test.js +25 -0
- package/lib/__tests__/useSafeTimeout.test.d.ts +1 -0
- package/lib/__tests__/useSafeTimeout.test.js +45 -0
- package/lib/stories/ActionList.stories.js +454 -0
- package/lib/stories/ActionMenu.stories.js +350 -0
- package/lib/stories/AnchoredOverlay.stories.js +127 -0
- package/lib/stories/Autocomplete.stories.js +619 -0
- package/lib/stories/AvatarStack.stories.js +49 -0
- package/lib/stories/Button.stories.js +125 -0
- package/lib/stories/ConfirmationDialog.stories.js +111 -0
- package/lib/stories/Dialog.stories.js +265 -0
- package/lib/stories/DropdownMenu.stories.js +122 -0
- package/lib/stories/IssueLabelToken.stories.js +165 -0
- package/lib/stories/Overlay.stories.js +204 -0
- package/lib/stories/Portal.stories.js +104 -0
- package/lib/stories/ProfileToken.stories.js +162 -0
- package/lib/stories/SelectPanel.stories.js +399 -0
- package/lib/stories/TextInputWithTokens.stories.js +235 -0
- package/lib/stories/ThemeProvider.stories.js +102 -0
- package/lib/stories/Token.stories.js +159 -0
- package/lib/stories/useAnchoredPosition.stories.js +351 -0
- package/lib/stories/useFocusTrap.stories.js +356 -0
- package/lib/stories/useFocusZone.stories.js +599 -0
- package/lib-esm/TextInputWithTokens.js +17 -10
- package/lib-esm/Token/Token.js +13 -2
- package/lib-esm/Token/TokenBase.js +0 -4
- package/lib-esm/Token/_RemoveTokenButton.js +11 -2
- package/lib-esm/__tests__/ActionList.test.d.ts +1 -0
- package/lib-esm/__tests__/ActionList.test.js +57 -0
- package/lib-esm/__tests__/ActionList.types.test.d.ts +6 -0
- package/lib-esm/__tests__/ActionList.types.test.js +45 -0
- package/lib-esm/__tests__/ActionMenu.test.d.ts +1 -0
- package/lib-esm/__tests__/ActionMenu.test.js +139 -0
- package/lib-esm/__tests__/AnchoredOverlay.test.d.ts +1 -0
- package/lib-esm/__tests__/AnchoredOverlay.test.js +134 -0
- package/lib-esm/__tests__/Autocomplete.test.d.ts +1 -0
- package/lib-esm/__tests__/Autocomplete.test.js +494 -0
- package/lib-esm/__tests__/Avatar.test.d.ts +1 -0
- package/lib-esm/__tests__/Avatar.test.js +56 -0
- package/lib-esm/__tests__/AvatarStack.test.d.ts +1 -0
- package/lib-esm/__tests__/AvatarStack.test.js +58 -0
- package/lib-esm/__tests__/BorderBox.test.d.ts +1 -0
- package/lib-esm/__tests__/BorderBox.test.js +47 -0
- package/lib-esm/__tests__/Box.test.d.ts +1 -0
- package/lib-esm/__tests__/Box.test.js +67 -0
- package/lib-esm/__tests__/BranchName.test.d.ts +1 -0
- package/lib-esm/__tests__/BranchName.test.js +26 -0
- package/lib-esm/__tests__/Breadcrumbs.test.d.ts +1 -0
- package/lib-esm/__tests__/Breadcrumbs.test.js +27 -0
- package/lib-esm/__tests__/BreadcrumbsItem.test.d.ts +1 -0
- package/lib-esm/__tests__/BreadcrumbsItem.test.js +39 -0
- package/lib-esm/__tests__/Button.test.d.ts +1 -0
- package/lib-esm/__tests__/Button.test.js +133 -0
- package/lib-esm/__tests__/Caret.test.d.ts +1 -0
- package/lib-esm/__tests__/Caret.test.js +42 -0
- package/lib-esm/__tests__/CircleBadge.test.d.ts +1 -0
- package/lib-esm/__tests__/CircleBadge.test.js +70 -0
- package/lib-esm/__tests__/CircleOcticon.test.d.ts +1 -0
- package/lib-esm/__tests__/CircleOcticon.test.js +59 -0
- package/lib-esm/__tests__/ConfirmationDialog.test.d.ts +1 -0
- package/lib-esm/__tests__/ConfirmationDialog.test.js +113 -0
- package/lib-esm/__tests__/CounterLabel.test.d.ts +1 -0
- package/lib-esm/__tests__/CounterLabel.test.js +47 -0
- package/lib-esm/__tests__/Details.test.d.ts +1 -0
- package/lib-esm/__tests__/Details.test.js +107 -0
- package/lib-esm/__tests__/Dialog.test.d.ts +1 -0
- package/lib-esm/__tests__/Dialog.test.js +171 -0
- package/lib-esm/__tests__/Dropdown.test.d.ts +1 -0
- package/lib-esm/__tests__/Dropdown.test.js +53 -0
- package/lib-esm/__tests__/DropdownMenu.test.d.ts +1 -0
- package/lib-esm/__tests__/DropdownMenu.test.js +137 -0
- package/lib-esm/__tests__/FilterList.test.d.ts +1 -0
- package/lib-esm/__tests__/FilterList.test.js +26 -0
- package/lib-esm/__tests__/FilterListItem.test.d.ts +1 -0
- package/lib-esm/__tests__/FilterListItem.test.js +36 -0
- package/lib-esm/__tests__/FilteredSearch.test.d.ts +1 -0
- package/lib-esm/__tests__/FilteredSearch.test.js +26 -0
- package/lib-esm/__tests__/Flash.test.d.ts +1 -0
- package/lib-esm/__tests__/Flash.test.js +51 -0
- package/lib-esm/__tests__/Flex.test.d.ts +1 -0
- package/lib-esm/__tests__/Flex.test.js +64 -0
- package/lib-esm/__tests__/FormGroup.test.d.ts +1 -0
- package/lib-esm/__tests__/FormGroup.test.js +44 -0
- package/lib-esm/__tests__/Grid.test.d.ts +1 -0
- package/lib-esm/__tests__/Grid.test.js +94 -0
- package/lib-esm/__tests__/Header.test.d.ts +1 -0
- package/lib-esm/__tests__/Header.test.js +48 -0
- package/lib-esm/__tests__/Heading.test.d.ts +1 -0
- package/lib-esm/__tests__/Heading.test.js +99 -0
- package/lib-esm/__tests__/Label.test.d.ts +1 -0
- package/lib-esm/__tests__/Label.test.js +36 -0
- package/lib-esm/__tests__/LabelGroup.test.d.ts +1 -0
- package/lib-esm/__tests__/LabelGroup.test.js +26 -0
- package/lib-esm/__tests__/Link.test.d.ts +1 -0
- package/lib-esm/__tests__/Link.test.js +60 -0
- package/lib-esm/__tests__/Merge.types.test.d.ts +30 -0
- package/lib-esm/__tests__/Merge.types.test.js +14 -0
- package/lib-esm/__tests__/Overlay.test.d.ts +1 -0
- package/lib-esm/__tests__/Overlay.test.js +123 -0
- package/lib-esm/__tests__/Pagehead.test.d.ts +1 -0
- package/lib-esm/__tests__/Pagehead.test.js +26 -0
- package/lib-esm/__tests__/Pagination/Pagination.test.d.ts +1 -0
- package/lib-esm/__tests__/Pagination/Pagination.test.js +35 -0
- package/lib-esm/__tests__/Pagination/PaginationModel.test.d.ts +1 -0
- package/lib-esm/__tests__/Pagination/PaginationModel.test.js +182 -0
- package/lib-esm/__tests__/PointerBox.test.d.ts +1 -0
- package/lib-esm/__tests__/PointerBox.test.js +36 -0
- package/lib-esm/__tests__/Popover.test.d.ts +1 -0
- package/lib-esm/__tests__/Popover.test.js +53 -0
- package/lib-esm/__tests__/Portal.test.d.ts +1 -0
- package/lib-esm/__tests__/Portal.test.js +104 -0
- package/lib-esm/__tests__/Position.test.d.ts +1 -0
- package/lib-esm/__tests__/Position.test.js +133 -0
- package/lib-esm/__tests__/ProgressBar.test.d.ts +1 -0
- package/lib-esm/__tests__/ProgressBar.test.js +58 -0
- package/lib-esm/__tests__/SelectMenu.test.d.ts +1 -0
- package/lib-esm/__tests__/SelectMenu.test.js +145 -0
- package/lib-esm/__tests__/SelectPanel.test.d.ts +1 -0
- package/lib-esm/__tests__/SelectPanel.test.js +65 -0
- package/lib-esm/__tests__/SideNav.test.d.ts +1 -0
- package/lib-esm/__tests__/SideNav.test.js +60 -0
- package/lib-esm/__tests__/Spinner.test.d.ts +1 -0
- package/lib-esm/__tests__/Spinner.test.js +43 -0
- package/lib-esm/__tests__/StateLabel.test.d.ts +1 -0
- package/lib-esm/__tests__/StateLabel.test.js +61 -0
- package/lib-esm/__tests__/StyledOcticon.test.d.ts +1 -0
- package/lib-esm/__tests__/StyledOcticon.test.js +29 -0
- package/lib-esm/__tests__/SubNav.test.d.ts +1 -0
- package/lib-esm/__tests__/SubNav.test.js +50 -0
- package/lib-esm/__tests__/SubNavLink.test.d.ts +1 -0
- package/lib-esm/__tests__/SubNavLink.test.js +39 -0
- package/lib-esm/__tests__/TabNav.test.d.ts +1 -0
- package/lib-esm/__tests__/TabNav.test.js +39 -0
- package/lib-esm/__tests__/Text.test.d.ts +1 -0
- package/lib-esm/__tests__/Text.test.js +93 -0
- package/lib-esm/__tests__/TextInput.test.d.ts +1 -0
- package/lib-esm/__tests__/TextInput.test.js +68 -0
- package/lib-esm/__tests__/TextInputWithTokens.test.d.ts +1 -0
- package/lib-esm/__tests__/TextInputWithTokens.test.js +341 -0
- package/lib-esm/__tests__/ThemeProvider.test.d.ts +1 -0
- package/lib-esm/__tests__/ThemeProvider.test.js +408 -0
- package/lib-esm/__tests__/Timeline.test.d.ts +1 -0
- package/lib-esm/__tests__/Timeline.test.js +65 -0
- package/lib-esm/__tests__/Token.test.d.ts +1 -0
- package/lib-esm/__tests__/Token.test.js +166 -0
- package/lib-esm/__tests__/Tooltip.test.d.ts +1 -0
- package/lib-esm/__tests__/Tooltip.test.js +59 -0
- package/lib-esm/__tests__/Truncate.test.d.ts +1 -0
- package/lib-esm/__tests__/Truncate.test.js +53 -0
- package/lib-esm/__tests__/UnderlineNav.test.d.ts +1 -0
- package/lib-esm/__tests__/UnderlineNav.test.js +60 -0
- package/lib-esm/__tests__/UnderlineNavLink.test.d.ts +1 -0
- package/lib-esm/__tests__/UnderlineNavLink.test.js +41 -0
- package/lib-esm/__tests__/behaviors/anchoredPosition.test.d.ts +1 -0
- package/lib-esm/__tests__/behaviors/anchoredPosition.test.js +388 -0
- package/lib-esm/__tests__/behaviors/focusTrap.test.d.ts +1 -0
- package/lib-esm/__tests__/behaviors/focusTrap.test.js +227 -0
- package/lib-esm/__tests__/behaviors/focusZone.test.d.ts +1 -0
- package/lib-esm/__tests__/behaviors/focusZone.test.js +487 -0
- package/lib-esm/__tests__/behaviors/iterateFocusableElements.test.d.ts +1 -0
- package/lib-esm/__tests__/behaviors/iterateFocusableElements.test.js +48 -0
- package/lib-esm/__tests__/behaviors/scrollIntoViewingArea.test.d.ts +1 -0
- package/lib-esm/__tests__/behaviors/scrollIntoViewingArea.test.js +224 -0
- package/lib-esm/__tests__/filterObject.test.d.ts +1 -0
- package/lib-esm/__tests__/filterObject.test.js +27 -0
- package/lib-esm/__tests__/hooks/useAnchoredPosition.test.d.ts +1 -0
- package/lib-esm/__tests__/hooks/useAnchoredPosition.test.js +46 -0
- package/lib-esm/__tests__/hooks/useOnEscapePress.test.d.ts +1 -0
- package/lib-esm/__tests__/hooks/useOnEscapePress.test.js +23 -0
- package/lib-esm/__tests__/hooks/useOnOutsideClick.test.d.ts +1 -0
- package/lib-esm/__tests__/hooks/useOnOutsideClick.test.js +68 -0
- package/lib-esm/__tests__/hooks/useOpenAndCloseFocus.test.d.ts +1 -0
- package/lib-esm/__tests__/hooks/useOpenAndCloseFocus.test.js +52 -0
- package/lib-esm/__tests__/hooks/useProvidedStateOrCreate.test.d.ts +1 -0
- package/lib-esm/__tests__/hooks/useProvidedStateOrCreate.test.js +36 -0
- package/lib-esm/__tests__/theme.test.d.ts +1 -0
- package/lib-esm/__tests__/theme.test.js +33 -0
- package/lib-esm/__tests__/themeGet.test.d.ts +1 -0
- package/lib-esm/__tests__/themeGet.test.js +22 -0
- package/lib-esm/__tests__/useSafeTimeout.test.d.ts +1 -0
- package/lib-esm/__tests__/useSafeTimeout.test.js +39 -0
- package/lib-esm/stories/ActionList.stories.js +395 -0
- package/lib-esm/stories/ActionMenu.stories.js +305 -0
- package/lib-esm/stories/AnchoredOverlay.stories.js +101 -0
- package/lib-esm/stories/Autocomplete.stories.js +560 -0
- package/lib-esm/stories/AvatarStack.stories.js +32 -0
- package/lib-esm/stories/Button.stories.js +86 -0
- package/lib-esm/stories/ConfirmationDialog.stories.js +86 -0
- package/lib-esm/stories/Dialog.stories.js +240 -0
- package/lib-esm/stories/DropdownMenu.stories.js +94 -0
- package/lib-esm/stories/IssueLabelToken.stories.js +139 -0
- package/lib-esm/stories/Overlay.stories.js +173 -0
- package/lib-esm/stories/Portal.stories.js +68 -0
- package/lib-esm/stories/ProfileToken.stories.js +136 -0
- package/lib-esm/stories/SelectPanel.stories.js +334 -0
- package/lib-esm/stories/TextInputWithTokens.stories.js +196 -0
- package/lib-esm/stories/ThemeProvider.stories.js +83 -0
- package/lib-esm/stories/Token.stories.js +133 -0
- package/lib-esm/stories/useAnchoredPosition.stories.js +313 -0
- package/lib-esm/stories/useFocusTrap.stories.js +309 -0
- package/lib-esm/stories/useFocusZone.stories.js +554 -0
- package/migrating.md +250 -0
- package/now.json +17 -0
- package/package-lock.json +28456 -0
- package/package.json +6 -6
- package/rollup.config.js +36 -0
- package/script/build +19 -0
- package/script/build-storybook +10 -0
- package/script/setup +12 -0
- package/src/ActionList/Divider.tsx +25 -0
- package/src/ActionList/Group.tsx +45 -0
- package/src/ActionList/Header.tsx +74 -0
- package/src/ActionList/Item.tsx +496 -0
- package/src/ActionList/List.tsx +258 -0
- package/src/ActionList/index.ts +21 -0
- package/src/ActionMenu.tsx +106 -0
- package/src/AnchoredOverlay/AnchoredOverlay.tsx +191 -0
- package/src/AnchoredOverlay/index.ts +2 -0
- package/src/Autocomplete/Autocomplete.tsx +103 -0
- package/src/Autocomplete/AutocompleteContext.tsx +19 -0
- package/src/Autocomplete/AutocompleteInput.tsx +179 -0
- package/src/Autocomplete/AutocompleteMenu.tsx +341 -0
- package/src/Autocomplete/AutocompleteOverlay.tsx +68 -0
- package/src/Autocomplete/index.ts +2 -0
- package/src/Avatar.tsx +46 -0
- package/src/AvatarPair.tsx +35 -0
- package/src/AvatarStack.tsx +159 -0
- package/src/BaseStyles.tsx +53 -0
- package/src/BorderBox.tsx +18 -0
- package/src/Box.tsx +54 -0
- package/src/BranchName.tsx +19 -0
- package/src/Breadcrumbs.tsx +101 -0
- package/src/Button/Button.tsx +40 -0
- package/src/Button/ButtonBase.tsx +43 -0
- package/src/Button/ButtonClose.tsx +40 -0
- package/src/Button/ButtonDanger.tsx +43 -0
- package/src/Button/ButtonGroup.tsx +55 -0
- package/src/Button/ButtonInvisible.tsx +32 -0
- package/src/Button/ButtonOutline.tsx +43 -0
- package/src/Button/ButtonPrimary.tsx +41 -0
- package/src/Button/ButtonStyles.tsx +36 -0
- package/src/Button/ButtonTableList.tsx +58 -0
- package/src/Button/index.ts +16 -0
- package/src/Caret.tsx +133 -0
- package/src/CircleBadge.tsx +55 -0
- package/src/CircleOcticon.tsx +37 -0
- package/src/CounterLabel.tsx +52 -0
- package/src/Details.tsx +23 -0
- package/src/Dialog/ConfirmationDialog.tsx +184 -0
- package/src/Dialog/Dialog.tsx +432 -0
- package/src/Dialog.tsx +149 -0
- package/src/Dropdown.tsx +158 -0
- package/src/DropdownMenu/DropdownButton.tsx +15 -0
- package/src/DropdownMenu/DropdownMenu.tsx +115 -0
- package/src/DropdownMenu/index.ts +4 -0
- package/src/DropdownStyles.ts +128 -0
- package/src/FilterList.tsx +81 -0
- package/src/FilteredActionList/FilteredActionList.tsx +142 -0
- package/src/FilteredActionList/index.ts +2 -0
- package/src/FilteredSearch.tsx +28 -0
- package/src/Flash.tsx +77 -0
- package/src/Flex.tsx +15 -0
- package/src/FormGroup.tsx +27 -0
- package/src/Grid.tsx +15 -0
- package/src/Header.tsx +84 -0
- package/src/Heading.tsx +21 -0
- package/src/Label.tsx +75 -0
- package/src/LabelGroup.tsx +18 -0
- package/src/Link.tsx +46 -0
- package/src/Overlay.tsx +197 -0
- package/src/Pagehead.tsx +17 -0
- package/src/Pagination/Pagination.tsx +214 -0
- package/src/Pagination/index.ts +4 -0
- package/src/Pagination/model.tsx +187 -0
- package/src/PointerBox.tsx +31 -0
- package/src/Popover.tsx +236 -0
- package/src/Portal/Portal.tsx +96 -0
- package/src/Portal/index.ts +5 -0
- package/src/Position.tsx +63 -0
- package/src/ProgressBar.tsx +52 -0
- package/src/SelectMenu/SelectMenu.tsx +125 -0
- package/src/SelectMenu/SelectMenuContext.tsx +9 -0
- package/src/SelectMenu/SelectMenuDivider.tsx +25 -0
- package/src/SelectMenu/SelectMenuFilter.tsx +51 -0
- package/src/SelectMenu/SelectMenuFooter.tsx +28 -0
- package/src/SelectMenu/SelectMenuHeader.tsx +50 -0
- package/src/SelectMenu/SelectMenuItem.tsx +137 -0
- package/src/SelectMenu/SelectMenuList.tsx +42 -0
- package/src/SelectMenu/SelectMenuLoadingAnimation.tsx +24 -0
- package/src/SelectMenu/SelectMenuModal.tsx +121 -0
- package/src/SelectMenu/SelectMenuTab.tsx +88 -0
- package/src/SelectMenu/SelectMenuTabPanel.tsx +30 -0
- package/src/SelectMenu/SelectMenuTabs.tsx +44 -0
- package/src/SelectMenu/hooks/useKeyboardNav.js +90 -0
- package/src/SelectMenu/index.ts +15 -0
- package/src/SelectPanel/SelectPanel.tsx +173 -0
- package/src/SelectPanel/index.ts +2 -0
- package/src/SideNav.tsx +193 -0
- package/src/Spinner.tsx +59 -0
- package/src/StateLabel.tsx +102 -0
- package/src/StyledOcticon.tsx +24 -0
- package/src/SubNav.tsx +129 -0
- package/src/TabNav.tsx +77 -0
- package/src/Text.tsx +13 -0
- package/src/TextInput.tsx +68 -0
- package/src/TextInputWithTokens.tsx +280 -0
- package/src/ThemeProvider.tsx +176 -0
- package/src/Timeline.tsx +141 -0
- package/src/Token/AvatarToken.tsx +54 -0
- package/src/Token/IssueLabelToken.tsx +150 -0
- package/src/Token/Token.tsx +126 -0
- package/src/Token/TokenBase.tsx +129 -0
- package/src/Token/_RemoveTokenButton.tsx +111 -0
- package/src/Token/_TokenTextContainer.tsx +47 -0
- package/src/Token/index.ts +3 -0
- package/src/Tooltip.tsx +263 -0
- package/src/Truncate.tsx +36 -0
- package/src/UnderlineNav.tsx +110 -0
- package/src/_TextInputWrapper.tsx +105 -0
- package/src/_UnstyledTextInput.tsx +19 -0
- package/src/__tests__/.eslintrc.json +11 -0
- package/src/__tests__/ActionList.test.tsx +53 -0
- package/src/__tests__/ActionList.types.test.tsx +51 -0
- package/src/__tests__/ActionMenu.test.tsx +136 -0
- package/src/__tests__/AnchoredOverlay.test.tsx +150 -0
- package/src/__tests__/Autocomplete.test.tsx +444 -0
- package/src/__tests__/Avatar.test.tsx +44 -0
- package/src/__tests__/AvatarStack.test.tsx +48 -0
- package/src/__tests__/BorderBox.test.tsx +43 -0
- package/src/__tests__/Box.test.tsx +42 -0
- package/src/__tests__/BranchName.test.tsx +26 -0
- package/src/__tests__/Breadcrumbs.test.tsx +27 -0
- package/src/__tests__/BreadcrumbsItem.test.tsx +31 -0
- package/src/__tests__/Button.test.tsx +128 -0
- package/src/__tests__/Caret.test.tsx +36 -0
- package/src/__tests__/CircleBadge.test.tsx +66 -0
- package/src/__tests__/CircleOcticon.test.tsx +50 -0
- package/src/__tests__/ConfirmationDialog.test.tsx +120 -0
- package/src/__tests__/CounterLabel.test.tsx +50 -0
- package/src/__tests__/Details.test.tsx +115 -0
- package/src/__tests__/Dialog.test.tsx +155 -0
- package/src/__tests__/Dropdown.test.tsx +53 -0
- package/src/__tests__/DropdownMenu.test.tsx +136 -0
- package/src/__tests__/FilterList.test.tsx +26 -0
- package/src/__tests__/FilterListItem.test.tsx +31 -0
- package/src/__tests__/FilteredSearch.test.tsx +26 -0
- package/src/__tests__/Flash.test.tsx +45 -0
- package/src/__tests__/Flex.test.tsx +58 -0
- package/src/__tests__/FormGroup.test.tsx +38 -0
- package/src/__tests__/Grid.test.tsx +82 -0
- package/src/__tests__/Header.test.tsx +49 -0
- package/src/__tests__/Heading.test.tsx +91 -0
- package/src/__tests__/Label.test.tsx +34 -0
- package/src/__tests__/LabelGroup.test.tsx +30 -0
- package/src/__tests__/Link.test.tsx +47 -0
- package/src/__tests__/Merge.types.test.ts +39 -0
- package/src/__tests__/Overlay.test.tsx +103 -0
- package/src/__tests__/Pagehead.test.tsx +23 -0
- package/src/__tests__/Pagination/Pagination.test.tsx +30 -0
- package/src/__tests__/Pagination/PaginationModel.test.tsx +133 -0
- package/src/__tests__/Pagination/__snapshots__/Pagination.test.tsx.snap +184 -0
- package/src/__tests__/PointerBox.test.tsx +34 -0
- package/src/__tests__/Popover.test.tsx +68 -0
- package/src/__tests__/Portal.test.tsx +103 -0
- package/src/__tests__/Position.test.tsx +117 -0
- package/src/__tests__/ProgressBar.test.tsx +40 -0
- package/src/__tests__/SelectMenu.test.tsx +142 -0
- package/src/__tests__/SelectPanel.test.tsx +63 -0
- package/src/__tests__/SideNav.test.tsx +62 -0
- package/src/__tests__/Spinner.test.tsx +42 -0
- package/src/__tests__/StateLabel.test.tsx +48 -0
- package/src/__tests__/StyledOcticon.test.tsx +26 -0
- package/src/__tests__/SubNav.test.tsx +50 -0
- package/src/__tests__/SubNavLink.test.tsx +31 -0
- package/src/__tests__/TabNav.test.tsx +32 -0
- package/src/__tests__/Text.test.tsx +78 -0
- package/src/__tests__/TextInput.test.tsx +49 -0
- package/src/__tests__/TextInputWithTokens.test.tsx +262 -0
- package/src/__tests__/ThemeProvider.test.tsx +441 -0
- package/src/__tests__/Timeline.test.tsx +58 -0
- package/src/__tests__/Token.test.tsx +118 -0
- package/src/__tests__/Tooltip.test.tsx +52 -0
- package/src/__tests__/Truncate.test.tsx +43 -0
- package/src/__tests__/UnderlineNav.test.tsx +58 -0
- package/src/__tests__/UnderlineNavLink.test.tsx +31 -0
- package/src/__tests__/__snapshots__/ActionList.test.tsx.snap +223 -0
- package/src/__tests__/__snapshots__/ActionMenu.test.tsx.snap +80 -0
- package/src/__tests__/__snapshots__/AnchoredOverlay.test.tsx.snap +332 -0
- package/src/__tests__/__snapshots__/Autocomplete.test.tsx.snap +3414 -0
- package/src/__tests__/__snapshots__/Avatar.test.tsx.snap +19 -0
- package/src/__tests__/__snapshots__/AvatarStack.test.tsx.snap +377 -0
- package/src/__tests__/__snapshots__/BorderBox.test.tsx.snap +14 -0
- package/src/__tests__/__snapshots__/Box.test.tsx.snap +201 -0
- package/src/__tests__/__snapshots__/BranchName.test.tsx.snap +17 -0
- package/src/__tests__/__snapshots__/Breadcrumbs.test.tsx.snap +29 -0
- package/src/__tests__/__snapshots__/BreadcrumbsItem.test.tsx.snap +79 -0
- package/src/__tests__/__snapshots__/Button.test.tsx.snap +840 -0
- package/src/__tests__/__snapshots__/Caret.test.tsx.snap +373 -0
- package/src/__tests__/__snapshots__/CircleBadge.test.tsx.snap +141 -0
- package/src/__tests__/__snapshots__/CircleOcticon.test.tsx.snap +64 -0
- package/src/__tests__/__snapshots__/ConfirmationDialog.test.tsx.snap +89 -0
- package/src/__tests__/__snapshots__/CounterLabel.test.tsx.snap +22 -0
- package/src/__tests__/__snapshots__/Details.test.tsx.snap +15 -0
- package/src/__tests__/__snapshots__/Dialog.test.tsx.snap +200 -0
- package/src/__tests__/__snapshots__/Dropdown.test.tsx.snap +249 -0
- package/src/__tests__/__snapshots__/DropdownMenu.test.tsx.snap +106 -0
- package/src/__tests__/__snapshots__/FilterList.test.tsx.snap +13 -0
- package/src/__tests__/__snapshots__/FilterListItem.test.tsx.snap +80 -0
- package/src/__tests__/__snapshots__/FilteredSearch.test.tsx.snap +32 -0
- package/src/__tests__/__snapshots__/Flash.test.tsx.snap +32 -0
- package/src/__tests__/__snapshots__/Flex.test.tsx.snap +130 -0
- package/src/__tests__/__snapshots__/FormGroup.test.tsx.snap +25 -0
- package/src/__tests__/__snapshots__/Grid.test.tsx.snap +178 -0
- package/src/__tests__/__snapshots__/Header.test.tsx.snap +79 -0
- package/src/__tests__/__snapshots__/Heading.test.tsx.snap +13 -0
- package/src/__tests__/__snapshots__/Label.test.tsx.snap +74 -0
- package/src/__tests__/__snapshots__/LabelGroup.test.tsx.snap +15 -0
- package/src/__tests__/__snapshots__/Link.test.tsx.snap +213 -0
- package/src/__tests__/__snapshots__/Pagehead.test.tsx.snap +15 -0
- package/src/__tests__/__snapshots__/PointerBox.test.tsx.snap +174 -0
- package/src/__tests__/__snapshots__/Popover.test.tsx.snap +4687 -0
- package/src/__tests__/__snapshots__/Position.test.tsx.snap +44 -0
- package/src/__tests__/__snapshots__/ProgressBar.test.tsx.snap +53 -0
- package/src/__tests__/__snapshots__/SelectMenu.test.tsx.snap +469 -0
- package/src/__tests__/__snapshots__/SelectPanel.test.tsx.snap +123 -0
- package/src/__tests__/__snapshots__/SideNav.test.tsx.snap +143 -0
- package/src/__tests__/__snapshots__/Spinner.test.tsx.snap +33 -0
- package/src/__tests__/__snapshots__/StateLabel.test.tsx.snap +388 -0
- package/src/__tests__/__snapshots__/StyledOcticon.test.tsx.snap +25 -0
- package/src/__tests__/__snapshots__/SubNav.test.tsx.snap +44 -0
- package/src/__tests__/__snapshots__/SubNavLink.test.tsx.snap +199 -0
- package/src/__tests__/__snapshots__/TabNav.test.tsx.snap +58 -0
- package/src/__tests__/__snapshots__/Text.test.tsx.snap +7 -0
- package/src/__tests__/__snapshots__/TextInput.test.tsx.snap +440 -0
- package/src/__tests__/__snapshots__/TextInputWithTokens.test.tsx.snap +5516 -0
- package/src/__tests__/__snapshots__/ThemeProvider.test.tsx.snap +15 -0
- package/src/__tests__/__snapshots__/Timeline.test.tsx.snap +159 -0
- package/src/__tests__/__snapshots__/Token.test.tsx.snap +3794 -0
- package/src/__tests__/__snapshots__/Tooltip.test.tsx.snap +227 -0
- package/src/__tests__/__snapshots__/Truncate.test.tsx.snap +17 -0
- package/src/__tests__/__snapshots__/UnderlineNav.test.tsx.snap +59 -0
- package/src/__tests__/__snapshots__/UnderlineNavLink.test.tsx.snap +130 -0
- package/src/__tests__/behaviors/anchoredPosition.test.ts +295 -0
- package/src/__tests__/behaviors/focusTrap.test.tsx +236 -0
- package/src/__tests__/behaviors/focusZone.test.tsx +549 -0
- package/src/__tests__/behaviors/iterateFocusableElements.test.tsx +61 -0
- package/src/__tests__/behaviors/scrollIntoViewingArea.test.ts +195 -0
- package/src/__tests__/filterObject.test.ts +54 -0
- package/src/__tests__/hooks/useAnchoredPosition.test.tsx +31 -0
- package/src/__tests__/hooks/useOnEscapePress.test.tsx +16 -0
- package/src/__tests__/hooks/useOnOutsideClick.test.tsx +48 -0
- package/src/__tests__/hooks/useOpenAndCloseFocus.test.tsx +48 -0
- package/src/__tests__/hooks/useProvidedStateOrCreate.test.tsx +39 -0
- package/src/__tests__/theme.test.ts +41 -0
- package/src/__tests__/themeGet.test.ts +15 -0
- package/src/__tests__/useSafeTimeout.test.tsx +36 -0
- package/src/behaviors/anchoredPosition.ts +442 -0
- package/src/behaviors/focusTrap.ts +184 -0
- package/src/behaviors/focusZone.ts +713 -0
- package/src/behaviors/scrollIntoViewingArea.ts +27 -0
- package/src/constants.ts +62 -0
- package/src/hooks/index.ts +11 -0
- package/src/hooks/useAnchoredPosition.ts +53 -0
- package/src/hooks/useCombinedRefs.ts +40 -0
- package/src/hooks/useDetails.tsx +54 -0
- package/src/hooks/useDialog.ts +121 -0
- package/src/hooks/useFocusTrap.ts +80 -0
- package/src/hooks/useFocusZone.ts +64 -0
- package/src/hooks/useOnEscapePress.ts +63 -0
- package/src/hooks/useOnOutsideClick.tsx +82 -0
- package/src/hooks/useOpenAndCloseFocus.ts +32 -0
- package/src/hooks/useOverlay.tsx +34 -0
- package/src/hooks/useProvidedRefOrCreate.ts +14 -0
- package/src/hooks/useProvidedStateOrCreate.ts +27 -0
- package/src/hooks/useRenderForcingRef.ts +22 -0
- package/src/hooks/useResizeObserver.ts +11 -0
- package/src/hooks/useSafeTimeout.ts +38 -0
- package/src/hooks/useScrollFlash.ts +21 -0
- package/src/index.ts +170 -0
- package/src/polyfills/eventListenerSignal.ts +66 -0
- package/src/stories/ActionList.stories.tsx +436 -0
- package/src/stories/ActionMenu.stories.tsx +334 -0
- package/src/stories/AnchoredOverlay.stories.tsx +117 -0
- package/src/stories/Autocomplete.stories.tsx +655 -0
- package/src/stories/AvatarStack.stories.tsx +37 -0
- package/src/stories/Button.stories.tsx +92 -0
- package/src/stories/ConfirmationDialog.stories.tsx +105 -0
- package/src/stories/Dialog.stories.tsx +240 -0
- package/src/stories/DropdownMenu.stories.tsx +84 -0
- package/src/stories/IssueLabelToken.stories.tsx +138 -0
- package/src/stories/Overlay.stories.tsx +213 -0
- package/src/stories/Portal.stories.tsx +109 -0
- package/src/stories/ProfileToken.stories.tsx +129 -0
- package/src/stories/SelectPanel.stories.tsx +353 -0
- package/src/stories/TextInputWithTokens.stories.tsx +146 -0
- package/src/stories/ThemeProvider.stories.tsx +104 -0
- package/src/stories/Token.stories.tsx +126 -0
- package/src/stories/useAnchoredPosition.stories.tsx +332 -0
- package/src/stories/useFocusTrap.stories.tsx +400 -0
- package/src/stories/useFocusZone.stories.tsx +663 -0
- package/src/sx.ts +9 -0
- package/src/theme-preval.js +79 -0
- package/src/theme.ts +3 -0
- package/src/utils/deprecate.tsx +73 -0
- package/src/utils/isNumeric.tsx +4 -0
- package/src/utils/iterateFocusableElements.ts +121 -0
- package/src/utils/ssr.tsx +1 -0
- package/src/utils/test-deprecations.tsx +19 -0
- package/src/utils/test-helpers.tsx +7 -0
- package/src/utils/test-matchers.tsx +109 -0
- package/src/utils/testing.tsx +242 -0
- package/src/utils/theme.js +64 -0
- package/src/utils/types/AriaRole.ts +71 -0
- package/src/utils/types/ComponentProps.ts +13 -0
- package/src/utils/types/Flatten.ts +4 -0
- package/src/utils/types/MandateProps.ts +19 -0
- package/src/utils/types/Merge.ts +20 -0
- package/src/utils/types/index.ts +5 -0
- package/src/utils/uniqueId.ts +6 -0
- package/src/utils/userAgent.ts +7 -0
- package/stats.html +3279 -0
- package/tsconfig.build.json +7 -0
- package/tsconfig.json +20 -0
@@ -0,0 +1,27 @@
|
|
1
|
+
export const scrollIntoViewingArea = (
|
2
|
+
child: HTMLElement,
|
3
|
+
viewingArea: HTMLElement,
|
4
|
+
direction: 'horizontal' | 'vertical' = 'vertical',
|
5
|
+
startMargin = 8,
|
6
|
+
endMargin = 0,
|
7
|
+
behavior: ScrollBehavior = 'smooth'
|
8
|
+
) => {
|
9
|
+
const startSide = direction === 'vertical' ? 'top' : 'left'
|
10
|
+
const endSide = direction === 'vertical' ? 'bottom' : 'right'
|
11
|
+
const scrollSide = direction === 'vertical' ? 'scrollTop' : 'scrollLeft'
|
12
|
+
const {[startSide]: childStart, [endSide]: childEnd} = child.getBoundingClientRect()
|
13
|
+
const {[startSide]: viewingAreaStart, [endSide]: viewingAreaEnd} = viewingArea.getBoundingClientRect()
|
14
|
+
|
15
|
+
const isChildStartAboveViewingArea = childStart < viewingAreaStart + endMargin
|
16
|
+
const isChildBottomBelowViewingArea = childEnd > viewingAreaEnd - startMargin
|
17
|
+
|
18
|
+
if (isChildStartAboveViewingArea) {
|
19
|
+
const scrollHeightToChildStart = childStart - viewingAreaStart + viewingArea[scrollSide]
|
20
|
+
viewingArea.scrollTo({behavior, [startSide]: scrollHeightToChildStart - endMargin})
|
21
|
+
} else if (isChildBottomBelowViewingArea) {
|
22
|
+
const scrollHeightToChildBottom = childEnd - viewingAreaEnd + viewingArea[scrollSide]
|
23
|
+
viewingArea.scrollTo({behavior, [startSide]: scrollHeightToChildBottom + startMargin})
|
24
|
+
}
|
25
|
+
|
26
|
+
// either completely in view or outside viewing area on both ends, don't scroll
|
27
|
+
}
|
package/src/constants.ts
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
import {themeGet} from '@styled-system/theme-get'
|
2
|
+
// eslint-disable-next-line import/no-namespace
|
3
|
+
import * as styledSystem from 'styled-system'
|
4
|
+
import theme from './theme'
|
5
|
+
|
6
|
+
const {get: getKey, compose, system} = styledSystem
|
7
|
+
|
8
|
+
export const get = (key: string) => themeGet(key, getKey(theme, key))
|
9
|
+
|
10
|
+
// Common props
|
11
|
+
|
12
|
+
export const COMMON = compose(styledSystem.space, styledSystem.color, styledSystem.display)
|
13
|
+
|
14
|
+
export interface SystemCommonProps
|
15
|
+
extends styledSystem.ColorProps,
|
16
|
+
styledSystem.SpaceProps,
|
17
|
+
styledSystem.DisplayProps {}
|
18
|
+
|
19
|
+
// Typography props
|
20
|
+
|
21
|
+
const whiteSpace = system({
|
22
|
+
whiteSpace: {
|
23
|
+
property: 'whiteSpace'
|
24
|
+
// cssProperty: 'whiteSpace',
|
25
|
+
}
|
26
|
+
})
|
27
|
+
|
28
|
+
export const TYPOGRAPHY = compose(styledSystem.typography, whiteSpace)
|
29
|
+
|
30
|
+
export interface SystemTypographyProps extends styledSystem.TypographyProps {
|
31
|
+
whiteSpace?: 'normal' | 'nowrap' | 'pre' | 'pre-wrap' | 'pre-line'
|
32
|
+
}
|
33
|
+
|
34
|
+
// Border props
|
35
|
+
|
36
|
+
export const BORDER = compose(styledSystem.border, styledSystem.shadow)
|
37
|
+
|
38
|
+
export interface SystemBorderProps extends styledSystem.BorderProps, styledSystem.ShadowProps {}
|
39
|
+
|
40
|
+
// Layout props
|
41
|
+
|
42
|
+
export const LAYOUT = styledSystem.layout
|
43
|
+
|
44
|
+
export type SystemLayoutProps = styledSystem.LayoutProps
|
45
|
+
|
46
|
+
// Position props
|
47
|
+
|
48
|
+
export const POSITION = styledSystem.position
|
49
|
+
|
50
|
+
export type SystemPositionProps = styledSystem.PositionProps
|
51
|
+
|
52
|
+
// Flex props
|
53
|
+
|
54
|
+
export const FLEX = styledSystem.flexbox
|
55
|
+
|
56
|
+
export type SystemFlexProps = styledSystem.FlexboxProps
|
57
|
+
|
58
|
+
// Grid props
|
59
|
+
|
60
|
+
export const GRID = styledSystem.grid
|
61
|
+
|
62
|
+
export type SystemGridProps = styledSystem.GridProps
|
@@ -0,0 +1,11 @@
|
|
1
|
+
export {useOnOutsideClick} from './useOnOutsideClick'
|
2
|
+
export type {UseOnOutsideClickSettings, TouchOrMouseEvent} from './useOnOutsideClick'
|
3
|
+
export {useProvidedRefOrCreate} from './useProvidedRefOrCreate'
|
4
|
+
export {useOnEscapePress} from './useOnEscapePress'
|
5
|
+
export {useOpenAndCloseFocus} from './useOpenAndCloseFocus'
|
6
|
+
export type {UseOpenAndCloseFocusSettings} from './useOpenAndCloseFocus'
|
7
|
+
export type {AnchoredPositionHookSettings} from './useAnchoredPosition'
|
8
|
+
export {useAnchoredPosition} from './useAnchoredPosition'
|
9
|
+
export {useOverlay} from './useOverlay'
|
10
|
+
export type {UseOverlaySettings} from './useOverlay'
|
11
|
+
export {useRenderForcingRef} from './useRenderForcingRef'
|
@@ -0,0 +1,53 @@
|
|
1
|
+
import React from 'react'
|
2
|
+
import {PositionSettings, getAnchoredPosition, AnchorPosition} from '../behaviors/anchoredPosition'
|
3
|
+
import {useProvidedRefOrCreate} from './useProvidedRefOrCreate'
|
4
|
+
import {useResizeObserver} from './useResizeObserver'
|
5
|
+
|
6
|
+
export interface AnchoredPositionHookSettings extends Partial<PositionSettings> {
|
7
|
+
floatingElementRef?: React.RefObject<Element>
|
8
|
+
anchorElementRef?: React.RefObject<Element>
|
9
|
+
}
|
10
|
+
|
11
|
+
/**
|
12
|
+
* Calculates the top and left values for an absolutely-positioned floating element
|
13
|
+
* to be anchored to some anchor element. Returns refs for the floating element
|
14
|
+
* and the anchor element, along with the position.
|
15
|
+
* @param settings Settings for calculating the anchored position.
|
16
|
+
* @param dependencies Dependencies to determine when to re-calculate the position.
|
17
|
+
* @returns An object of {top: number, left: number} to absolutely-position the
|
18
|
+
* floating element.
|
19
|
+
*/
|
20
|
+
export function useAnchoredPosition(
|
21
|
+
settings?: AnchoredPositionHookSettings,
|
22
|
+
dependencies: React.DependencyList = []
|
23
|
+
): {
|
24
|
+
floatingElementRef: React.RefObject<Element>
|
25
|
+
anchorElementRef: React.RefObject<Element>
|
26
|
+
position: AnchorPosition | undefined
|
27
|
+
} {
|
28
|
+
const floatingElementRef = useProvidedRefOrCreate(settings?.floatingElementRef)
|
29
|
+
const anchorElementRef = useProvidedRefOrCreate(settings?.anchorElementRef)
|
30
|
+
const [position, setPosition] = React.useState<AnchorPosition | undefined>(undefined)
|
31
|
+
|
32
|
+
const updatePosition = React.useCallback(
|
33
|
+
() => {
|
34
|
+
if (floatingElementRef.current instanceof Element && anchorElementRef.current instanceof Element) {
|
35
|
+
setPosition(getAnchoredPosition(floatingElementRef.current, anchorElementRef.current, settings))
|
36
|
+
} else {
|
37
|
+
setPosition(undefined)
|
38
|
+
}
|
39
|
+
},
|
40
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
41
|
+
[floatingElementRef, anchorElementRef, ...dependencies]
|
42
|
+
)
|
43
|
+
|
44
|
+
React.useLayoutEffect(updatePosition, [updatePosition])
|
45
|
+
|
46
|
+
useResizeObserver(updatePosition)
|
47
|
+
|
48
|
+
return {
|
49
|
+
floatingElementRef,
|
50
|
+
anchorElementRef,
|
51
|
+
position
|
52
|
+
}
|
53
|
+
}
|
@@ -0,0 +1,40 @@
|
|
1
|
+
import React, {ForwardedRef, useRef} from 'react'
|
2
|
+
|
3
|
+
/**
|
4
|
+
* Creates a ref by combining multiple constituent refs. The ref returned by this hook
|
5
|
+
* should be passed as the ref for the element that needs to be shared. This is
|
6
|
+
* particularly useful when you are using `React.forwardRef` in your component but you
|
7
|
+
* also want to be able to access the local element. This is a small anti-pattern,
|
8
|
+
* though, as it breaks encapsulation.
|
9
|
+
* @param refs
|
10
|
+
*/
|
11
|
+
export function useCombinedRefs<T>(...refs: (ForwardedRef<T> | null | undefined)[]) {
|
12
|
+
const combinedRef = useRef<T | null>(null)
|
13
|
+
|
14
|
+
React.useLayoutEffect(() => {
|
15
|
+
function setRefs(current: T | null = null) {
|
16
|
+
for (const ref of refs) {
|
17
|
+
if (!ref) {
|
18
|
+
return
|
19
|
+
}
|
20
|
+
if (typeof ref === 'function') {
|
21
|
+
ref(current)
|
22
|
+
} else {
|
23
|
+
ref.current = current
|
24
|
+
}
|
25
|
+
}
|
26
|
+
}
|
27
|
+
|
28
|
+
setRefs(combinedRef.current)
|
29
|
+
|
30
|
+
return () => {
|
31
|
+
// ensure the refs get updated on unmount
|
32
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
33
|
+
setRefs(combinedRef.current)
|
34
|
+
}
|
35
|
+
|
36
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
37
|
+
}, [...refs, combinedRef.current])
|
38
|
+
|
39
|
+
return combinedRef
|
40
|
+
}
|
@@ -0,0 +1,54 @@
|
|
1
|
+
import {useCallback, useEffect, useState, useRef} from 'react'
|
2
|
+
|
3
|
+
type UseDetailsParameters = {
|
4
|
+
ref?: React.RefObject<HTMLElement>
|
5
|
+
closeOnOutsideClick?: boolean
|
6
|
+
defaultOpen?: boolean
|
7
|
+
onClickOutside?: (event: MouseEvent) => void
|
8
|
+
}
|
9
|
+
|
10
|
+
function useDetails({ref, closeOnOutsideClick, defaultOpen, onClickOutside}: UseDetailsParameters) {
|
11
|
+
const [open, setOpen] = useState(defaultOpen)
|
12
|
+
const backupRef = useRef(null)
|
13
|
+
const customRef = ref ?? backupRef
|
14
|
+
|
15
|
+
const onClickOutsideInternal = useCallback(
|
16
|
+
(event: MouseEvent) => {
|
17
|
+
const {current} = customRef
|
18
|
+
const eventTarget = event.target as HTMLElement
|
19
|
+
const closest = eventTarget.closest('details') as HTMLDetailsElement
|
20
|
+
if (closest !== current) {
|
21
|
+
onClickOutside && onClickOutside(event)
|
22
|
+
if (!event.defaultPrevented) {
|
23
|
+
setOpen(false)
|
24
|
+
}
|
25
|
+
}
|
26
|
+
},
|
27
|
+
[customRef, setOpen, onClickOutside]
|
28
|
+
)
|
29
|
+
|
30
|
+
// handles the overlay behavior - closing the menu when clicking outside of it
|
31
|
+
useEffect(() => {
|
32
|
+
if (open && closeOnOutsideClick) {
|
33
|
+
document.addEventListener('click', onClickOutsideInternal)
|
34
|
+
return () => {
|
35
|
+
document.removeEventListener('click', onClickOutsideInternal)
|
36
|
+
}
|
37
|
+
}
|
38
|
+
}, [open, closeOnOutsideClick, onClickOutsideInternal])
|
39
|
+
|
40
|
+
const handleToggle = (e: React.SyntheticEvent<HTMLElement, Event>) => {
|
41
|
+
if (!e.defaultPrevented) {
|
42
|
+
const eventTarget = e.target as HTMLDetailsElement
|
43
|
+
setOpen(eventTarget.open)
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
const getDetailsProps = () => {
|
48
|
+
return {onToggle: handleToggle, open, ref: customRef}
|
49
|
+
}
|
50
|
+
|
51
|
+
return {open, setOpen, getDetailsProps}
|
52
|
+
}
|
53
|
+
|
54
|
+
export default useDetails
|
@@ -0,0 +1,121 @@
|
|
1
|
+
import {useCallback, useEffect} from 'react'
|
2
|
+
|
3
|
+
const noop = () => null
|
4
|
+
|
5
|
+
function visible(el: HTMLInputElement) {
|
6
|
+
return !el.hidden && (!el.type || el.type !== 'hidden') && (el.offsetWidth > 0 || el.offsetHeight > 0)
|
7
|
+
}
|
8
|
+
|
9
|
+
function focusable(el: Element) {
|
10
|
+
const inputEl = el as HTMLInputElement
|
11
|
+
return inputEl.tabIndex >= 0 && !inputEl.disabled && visible(inputEl)
|
12
|
+
}
|
13
|
+
|
14
|
+
type UseDialogParameters = {
|
15
|
+
modalRef: React.RefObject<HTMLElement>
|
16
|
+
overlayRef: React.RefObject<HTMLElement>
|
17
|
+
isOpen?: boolean
|
18
|
+
onDismiss?: () => void
|
19
|
+
initialFocusRef?: React.RefObject<HTMLElement>
|
20
|
+
closeButtonRef?: React.RefObject<HTMLElement>
|
21
|
+
returnFocusRef?: React.RefObject<HTMLElement>
|
22
|
+
}
|
23
|
+
|
24
|
+
function useDialog({
|
25
|
+
modalRef,
|
26
|
+
overlayRef,
|
27
|
+
isOpen,
|
28
|
+
onDismiss = noop,
|
29
|
+
initialFocusRef,
|
30
|
+
closeButtonRef
|
31
|
+
}: UseDialogParameters) {
|
32
|
+
const onClickOutside = useCallback(
|
33
|
+
e => {
|
34
|
+
if (
|
35
|
+
modalRef.current &&
|
36
|
+
overlayRef.current &&
|
37
|
+
!modalRef.current.contains(e.target) &&
|
38
|
+
overlayRef.current.contains(e.target)
|
39
|
+
) {
|
40
|
+
onDismiss()
|
41
|
+
}
|
42
|
+
},
|
43
|
+
[onDismiss, modalRef, overlayRef]
|
44
|
+
)
|
45
|
+
|
46
|
+
useEffect(() => {
|
47
|
+
if (isOpen) {
|
48
|
+
document.addEventListener('click', onClickOutside)
|
49
|
+
return () => {
|
50
|
+
document.removeEventListener('click', onClickOutside)
|
51
|
+
}
|
52
|
+
}
|
53
|
+
}, [isOpen, onClickOutside])
|
54
|
+
|
55
|
+
useEffect(() => {
|
56
|
+
if (isOpen) {
|
57
|
+
if (initialFocusRef && initialFocusRef.current) {
|
58
|
+
initialFocusRef.current.focus()
|
59
|
+
} else if (closeButtonRef && closeButtonRef.current) {
|
60
|
+
closeButtonRef.current.focus()
|
61
|
+
}
|
62
|
+
}
|
63
|
+
}, [isOpen, initialFocusRef, closeButtonRef])
|
64
|
+
|
65
|
+
const getFocusableItem = useCallback(
|
66
|
+
(e: Event, movement: number) => {
|
67
|
+
if (modalRef.current) {
|
68
|
+
const items = Array.from(modalRef.current.querySelectorAll('*')).filter(focusable)
|
69
|
+
if (items.length === 0) return
|
70
|
+
e.preventDefault()
|
71
|
+
const focusedElement = document.activeElement
|
72
|
+
if (!focusedElement) {
|
73
|
+
return
|
74
|
+
}
|
75
|
+
|
76
|
+
const index = items.indexOf(focusedElement)
|
77
|
+
const offsetIndex = index + movement
|
78
|
+
const fallbackIndex = movement === 1 ? 0 : items.length - 1
|
79
|
+
const focusableItem = items[offsetIndex] || items[fallbackIndex]
|
80
|
+
return focusableItem as HTMLElement
|
81
|
+
}
|
82
|
+
},
|
83
|
+
[modalRef]
|
84
|
+
)
|
85
|
+
|
86
|
+
const handleTab = useCallback(
|
87
|
+
e => {
|
88
|
+
const movement = e.shiftKey ? -1 : 1
|
89
|
+
const focusableItem = getFocusableItem(e, movement)
|
90
|
+
if (!focusableItem) {
|
91
|
+
return
|
92
|
+
}
|
93
|
+
|
94
|
+
focusableItem.focus()
|
95
|
+
},
|
96
|
+
[getFocusableItem]
|
97
|
+
)
|
98
|
+
|
99
|
+
const onKeyDown = useCallback(
|
100
|
+
event => {
|
101
|
+
switch (event.key) {
|
102
|
+
case 'Tab':
|
103
|
+
handleTab(event)
|
104
|
+
break
|
105
|
+
case 'Escape':
|
106
|
+
onDismiss()
|
107
|
+
event.stopPropagation()
|
108
|
+
break
|
109
|
+
}
|
110
|
+
},
|
111
|
+
[handleTab, onDismiss]
|
112
|
+
)
|
113
|
+
|
114
|
+
const getDialogProps = () => {
|
115
|
+
return {onKeyDown}
|
116
|
+
}
|
117
|
+
|
118
|
+
return {getDialogProps}
|
119
|
+
}
|
120
|
+
|
121
|
+
export default useDialog
|
@@ -0,0 +1,80 @@
|
|
1
|
+
import React from 'react'
|
2
|
+
import {focusTrap} from '../behaviors/focusTrap'
|
3
|
+
import {useProvidedRefOrCreate} from './useProvidedRefOrCreate'
|
4
|
+
|
5
|
+
export interface FocusTrapHookSettings {
|
6
|
+
/**
|
7
|
+
* Ref that will be used for the trapping container. If not provided, one will
|
8
|
+
* be created by this hook and returned.
|
9
|
+
*/
|
10
|
+
containerRef?: React.RefObject<HTMLElement>
|
11
|
+
|
12
|
+
/**
|
13
|
+
* Ref for the element that should receive focus when the focus trap is first enabled. If
|
14
|
+
* not provided, one will be created by this hook and returned. Its use is optional.
|
15
|
+
*/
|
16
|
+
initialFocusRef?: React.RefObject<HTMLElement>
|
17
|
+
|
18
|
+
/**
|
19
|
+
* Set to true to disable the focus trap and clean up listeners. Can be re-enabled at
|
20
|
+
* any time.
|
21
|
+
*/
|
22
|
+
disabled?: boolean
|
23
|
+
|
24
|
+
/**
|
25
|
+
* If true, when this focus trap is cleaned up, restore focus to the element that had
|
26
|
+
* focus immediately before the focus trap was enabled. (Default: false)
|
27
|
+
*/
|
28
|
+
restoreFocusOnCleanUp?: boolean
|
29
|
+
}
|
30
|
+
|
31
|
+
/**
|
32
|
+
* Hook used to trap focus inside a container. Returns a ref that can be added to the container
|
33
|
+
* that should trap focus.
|
34
|
+
* @param settings {FocusTrapHookSettings}
|
35
|
+
*/
|
36
|
+
export function useFocusTrap(
|
37
|
+
settings?: FocusTrapHookSettings,
|
38
|
+
dependencies: React.DependencyList = []
|
39
|
+
): {containerRef: React.RefObject<HTMLElement>; initialFocusRef: React.RefObject<HTMLElement>} {
|
40
|
+
const containerRef = useProvidedRefOrCreate(settings?.containerRef)
|
41
|
+
const initialFocusRef = useProvidedRefOrCreate(settings?.initialFocusRef)
|
42
|
+
const disabled = settings?.disabled
|
43
|
+
const abortController = React.useRef<AbortController>()
|
44
|
+
const previousFocusedElement = React.useRef<Element | null>(null)
|
45
|
+
|
46
|
+
// If we are enabling a focus trap and haven't already stored the previously focused element
|
47
|
+
// go ahead an do that so we can restore later when the trap is disabled.
|
48
|
+
if (!previousFocusedElement.current && !settings?.disabled) {
|
49
|
+
previousFocusedElement.current = document.activeElement
|
50
|
+
}
|
51
|
+
|
52
|
+
// This function removes the event listeners that enable the focus trap and restores focus
|
53
|
+
// to the previously-focused element (if necessary).
|
54
|
+
function disableTrap() {
|
55
|
+
abortController.current?.abort()
|
56
|
+
if (settings?.restoreFocusOnCleanUp && previousFocusedElement.current instanceof HTMLElement) {
|
57
|
+
previousFocusedElement.current.focus()
|
58
|
+
previousFocusedElement.current = null
|
59
|
+
}
|
60
|
+
}
|
61
|
+
|
62
|
+
React.useEffect(
|
63
|
+
() => {
|
64
|
+
if (containerRef.current instanceof HTMLElement) {
|
65
|
+
if (!disabled) {
|
66
|
+
abortController.current = focusTrap(containerRef.current, initialFocusRef.current ?? undefined)
|
67
|
+
return () => {
|
68
|
+
disableTrap()
|
69
|
+
}
|
70
|
+
} else {
|
71
|
+
disableTrap()
|
72
|
+
}
|
73
|
+
}
|
74
|
+
},
|
75
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
76
|
+
[containerRef, initialFocusRef, disabled, ...dependencies]
|
77
|
+
)
|
78
|
+
|
79
|
+
return {containerRef, initialFocusRef}
|
80
|
+
}
|
@@ -0,0 +1,64 @@
|
|
1
|
+
import React, {useEffect} from 'react'
|
2
|
+
import {focusZone, FocusZoneSettings} from '../behaviors/focusZone'
|
3
|
+
import {useProvidedRefOrCreate} from './useProvidedRefOrCreate'
|
4
|
+
|
5
|
+
export interface FocusZoneHookSettings extends Omit<FocusZoneSettings, 'activeDescendantControl'> {
|
6
|
+
/**
|
7
|
+
* Optional ref for the container that holds all elements participating in arrow key focus.
|
8
|
+
* If one is not passed, we will create one for you and return it from the hook.
|
9
|
+
*/
|
10
|
+
containerRef?: React.RefObject<HTMLElement>
|
11
|
+
|
12
|
+
/**
|
13
|
+
* If using the "active descendant" focus pattern, pass `true` or a ref to the controlling
|
14
|
+
* element. If a ref object is not passed, we will create one for you.
|
15
|
+
*/
|
16
|
+
activeDescendantFocus?: boolean | React.RefObject<HTMLElement>
|
17
|
+
|
18
|
+
/**
|
19
|
+
* Set to true to disable the focus zone and clean up listeners. Can be re-enabled at
|
20
|
+
* any time.
|
21
|
+
*/
|
22
|
+
disabled?: boolean
|
23
|
+
}
|
24
|
+
|
25
|
+
export function useFocusZone(
|
26
|
+
settings: FocusZoneHookSettings = {},
|
27
|
+
dependencies: React.DependencyList = []
|
28
|
+
): {containerRef: React.RefObject<HTMLElement>; activeDescendantControlRef: React.RefObject<HTMLElement>} {
|
29
|
+
const containerRef = useProvidedRefOrCreate(settings.containerRef)
|
30
|
+
const useActiveDescendant = !!settings.activeDescendantFocus
|
31
|
+
const passedActiveDescendantRef =
|
32
|
+
typeof settings.activeDescendantFocus === 'boolean' || !settings.activeDescendantFocus
|
33
|
+
? undefined
|
34
|
+
: settings.activeDescendantFocus
|
35
|
+
const activeDescendantControlRef = useProvidedRefOrCreate(passedActiveDescendantRef)
|
36
|
+
const disabled = settings.disabled
|
37
|
+
const abortController = React.useRef<AbortController>()
|
38
|
+
|
39
|
+
useEffect(
|
40
|
+
() => {
|
41
|
+
if (
|
42
|
+
containerRef.current instanceof HTMLElement &&
|
43
|
+
(!useActiveDescendant || activeDescendantControlRef.current instanceof HTMLElement)
|
44
|
+
) {
|
45
|
+
if (!disabled) {
|
46
|
+
const vanillaSettings: FocusZoneSettings = {
|
47
|
+
...settings,
|
48
|
+
activeDescendantControl: activeDescendantControlRef.current ?? undefined
|
49
|
+
}
|
50
|
+
abortController.current = focusZone(containerRef.current, vanillaSettings)
|
51
|
+
return () => {
|
52
|
+
abortController.current?.abort()
|
53
|
+
}
|
54
|
+
} else {
|
55
|
+
abortController.current?.abort()
|
56
|
+
}
|
57
|
+
}
|
58
|
+
},
|
59
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
60
|
+
[disabled, ...dependencies]
|
61
|
+
)
|
62
|
+
|
63
|
+
return {containerRef, activeDescendantControlRef}
|
64
|
+
}
|
@@ -0,0 +1,63 @@
|
|
1
|
+
import {useEffect, useCallback} from 'react'
|
2
|
+
|
3
|
+
const handlers: ((e: KeyboardEvent) => void)[] = []
|
4
|
+
|
5
|
+
/**
|
6
|
+
* Calls all handlers in reverse order
|
7
|
+
* @param event The KeyboardEvent generated by the Escape keydown.
|
8
|
+
*/
|
9
|
+
function handleEscape(event: KeyboardEvent) {
|
10
|
+
if (event.key === 'Escape' && !event.defaultPrevented) {
|
11
|
+
for (let i = handlers.length - 1; i >= 0; --i) {
|
12
|
+
handlers[i](event)
|
13
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
14
|
+
if (event.defaultPrevented) {
|
15
|
+
break
|
16
|
+
}
|
17
|
+
}
|
18
|
+
}
|
19
|
+
}
|
20
|
+
|
21
|
+
/**
|
22
|
+
* Sets up a `keydown` listener on `window.document`. If
|
23
|
+
* 1) The pressed key is "Escape", and
|
24
|
+
* 2) The event has not had `.preventDefault()` called
|
25
|
+
* The given callback will be executed.
|
26
|
+
*
|
27
|
+
* Note: If multiple `useOnEscapePress` hooks are active simultaneously, the
|
28
|
+
* callbacks will occur in reverse order. In other words, if a parent component
|
29
|
+
* and a child component both call `useOnEscapePress`, when the user presses
|
30
|
+
* Escape, the child component's callback will execute, followed by the parent's
|
31
|
+
* callback. Each callback has the chance to call `.preventDefault()` on the
|
32
|
+
* event to prevent further callbacks.
|
33
|
+
*
|
34
|
+
* @param callback {(e: KeyboardEvent) => void} The callback that gets executed
|
35
|
+
* when the Escape key is pressed. The KeyboardEvent generated by the Escape
|
36
|
+
* keypress is passed as the only argument.
|
37
|
+
*
|
38
|
+
* @param callbackDependencies {React.DependencyList} The dependencies of the given
|
39
|
+
* `onEscape` callback for memoization. Omit this param if the callback is already
|
40
|
+
* memoized. See `React.useCallback` for more info on memoization.
|
41
|
+
*/
|
42
|
+
export const useOnEscapePress = (
|
43
|
+
onEscape: (e: KeyboardEvent) => void,
|
44
|
+
callbackDependencies: React.DependencyList = [onEscape]
|
45
|
+
): void => {
|
46
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
47
|
+
const escapeCallback = useCallback(onEscape, callbackDependencies)
|
48
|
+
useEffect(() => {
|
49
|
+
if (handlers.length === 0) {
|
50
|
+
document.addEventListener('keydown', handleEscape)
|
51
|
+
}
|
52
|
+
handlers.push(escapeCallback)
|
53
|
+
return () => {
|
54
|
+
handlers.splice(
|
55
|
+
handlers.findIndex(h => h === escapeCallback),
|
56
|
+
1
|
57
|
+
)
|
58
|
+
if (handlers.length === 0) {
|
59
|
+
document.removeEventListener('keydown', handleEscape)
|
60
|
+
}
|
61
|
+
}
|
62
|
+
}, [escapeCallback])
|
63
|
+
}
|
@@ -0,0 +1,82 @@
|
|
1
|
+
import React, {useEffect, useCallback, useMemo} from 'react'
|
2
|
+
|
3
|
+
export type TouchOrMouseEvent = MouseEvent | TouchEvent
|
4
|
+
type TouchOrMouseEventCallback = (event: TouchOrMouseEvent) => boolean | undefined
|
5
|
+
|
6
|
+
export type UseOnOutsideClickSettings = {
|
7
|
+
containerRef: React.RefObject<HTMLDivElement>
|
8
|
+
ignoreClickRefs?: React.RefObject<HTMLElement>[]
|
9
|
+
onClickOutside: (e: TouchOrMouseEvent) => void
|
10
|
+
}
|
11
|
+
|
12
|
+
// Because events are handled at the document level, we provide a mechanism for early return.
|
13
|
+
const stopPropagation = true
|
14
|
+
|
15
|
+
/**
|
16
|
+
* Calls all handlers in reverse order
|
17
|
+
* @param event The MouseEvent generated by the click event.
|
18
|
+
*/
|
19
|
+
function handleClick(event: MouseEvent) {
|
20
|
+
if (!event.defaultPrevented) {
|
21
|
+
for (const handler of Object.values(registry).reverse()) {
|
22
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
23
|
+
if (handler(event) === stopPropagation || event.defaultPrevented) {
|
24
|
+
break
|
25
|
+
}
|
26
|
+
}
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
const registry: {[id: number]: TouchOrMouseEventCallback} = {}
|
31
|
+
|
32
|
+
function register(id: number, handler: TouchOrMouseEventCallback): void {
|
33
|
+
registry[id] = handler
|
34
|
+
}
|
35
|
+
|
36
|
+
function deregister(id: number) {
|
37
|
+
delete registry[id]
|
38
|
+
}
|
39
|
+
|
40
|
+
// For auto-incrementing unique identifiers for registered handlers.
|
41
|
+
let handlerId = 0
|
42
|
+
|
43
|
+
export const useOnOutsideClick = ({containerRef, ignoreClickRefs, onClickOutside}: UseOnOutsideClickSettings) => {
|
44
|
+
const id = useMemo(() => handlerId++, [])
|
45
|
+
|
46
|
+
const handler = useCallback<TouchOrMouseEventCallback>(
|
47
|
+
event => {
|
48
|
+
// don't call click handler if the mouse event was triggered by an auxiliary button (right click/wheel button/etc)
|
49
|
+
if (event instanceof MouseEvent && event.button > 0) {
|
50
|
+
return stopPropagation
|
51
|
+
}
|
52
|
+
|
53
|
+
// don't call handler if the click happened inside of the container
|
54
|
+
if (containerRef.current?.contains(event.target as Node)) {
|
55
|
+
return stopPropagation
|
56
|
+
}
|
57
|
+
|
58
|
+
// don't call handler if click happened on an ignored ref
|
59
|
+
if (ignoreClickRefs && ignoreClickRefs.some(({current}) => current?.contains(event.target as Node))) {
|
60
|
+
return stopPropagation
|
61
|
+
}
|
62
|
+
|
63
|
+
onClickOutside(event)
|
64
|
+
},
|
65
|
+
[containerRef, ignoreClickRefs, onClickOutside]
|
66
|
+
)
|
67
|
+
|
68
|
+
useEffect(() => {
|
69
|
+
if (Object.keys(registry).length === 0) {
|
70
|
+
// use capture to ensure we get all events
|
71
|
+
document.addEventListener('mousedown', handleClick, {capture: true})
|
72
|
+
}
|
73
|
+
register(id, handler)
|
74
|
+
|
75
|
+
return () => {
|
76
|
+
deregister(id)
|
77
|
+
if (Object.keys(registry).length === 0) {
|
78
|
+
document.removeEventListener('mousedown', handleClick, {capture: true})
|
79
|
+
}
|
80
|
+
}
|
81
|
+
}, [id, handler])
|
82
|
+
}
|