├── .changeset ├── README.md └── config.json ├── .editorconfig ├── .eslintrc ├── .github ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── Bug_report.md │ ├── Documentation.md │ ├── Feature_request.md │ └── Question.md ├── PULL_REQUEST_TEMPLATE.md ├── stale.yml └── workflows │ ├── release.yml │ └── test.yml ├── .gitignore ├── .npmrc ├── .nvmrc ├── .prettierignore ├── .prettierrc ├── HOUSEKEEPING.md ├── LICENSE ├── README.md ├── internal ├── dev │ ├── .eslintignore │ ├── .gitignore │ ├── package.json │ ├── tsconfig.json │ ├── tsup.d.ts │ ├── tsup.js │ └── types.ts ├── test │ ├── package.json │ ├── types.ts │ └── utils.tsx └── tsconfig │ ├── README.md │ ├── base.json │ ├── dom.json │ ├── package.json │ └── react-library.json ├── package.json ├── packages ├── accordion │ ├── .eslintignore │ ├── CHANGELOG.md │ ├── README.md │ ├── __tests__ │ │ ├── accordion-axe.test.tsx │ │ └── accordion.test.tsx │ ├── package.json │ ├── src │ │ └── reach-accordion.tsx │ ├── styles.css │ ├── tsconfig.json │ └── tsup.config.ts ├── alert-dialog │ ├── .eslintignore │ ├── CHANGELOG.md │ ├── README.md │ ├── __tests__ │ │ ├── alert-dialog-axe.test.tsx │ │ └── alert-dialog.test.tsx │ ├── package.json │ ├── src │ │ └── reach-alert-dialog.tsx │ ├── tsconfig.json │ └── tsup.config.ts ├── alert │ ├── .eslintignore │ ├── CHANGELOG.md │ ├── README.md │ ├── __tests__ │ │ └── alert-axe.test.tsx │ ├── package.json │ ├── src │ │ └── reach-alert.tsx │ ├── tsconfig.json │ └── tsup.config.ts ├── auto-id │ ├── .eslintignore │ ├── CHANGELOG.md │ ├── README.md │ ├── __tests__ │ │ ├── auto-id-axe.test.tsx │ │ └── auto-id.test.tsx │ ├── package.json │ ├── src │ │ └── reach-auto-id.ts │ ├── tsconfig.json │ └── tsup.config.ts ├── checkbox │ ├── .eslintignore │ ├── CHANGELOG.md │ ├── README.md │ ├── __tests__ │ │ └── checkbox-axe.test.tsx │ ├── package.json │ ├── src │ │ ├── custom.tsx │ │ ├── mixed.tsx │ │ └── reach-checkbox.ts │ ├── styles.css │ ├── tsconfig.json │ └── tsup.config.ts ├── combobox │ ├── .eslintignore │ ├── CHANGELOG.md │ ├── README.md │ ├── __tests__ │ │ ├── cities.ts │ │ ├── combobox-axe.test.tsx │ │ ├── combobox.test.tsx │ │ ├── latinize.d.ts │ │ └── utils.test.ts │ ├── package.json │ ├── src │ │ ├── reach-combobox.tsx │ │ └── utils.ts │ ├── styles.css │ ├── tsconfig.json │ └── tsup.config.ts ├── descendants │ ├── .eslintignore │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ └── reach-descendants.tsx │ ├── tsconfig.json │ └── tsup.config.ts ├── dialog │ ├── .eslintignore │ ├── CHANGELOG.md │ ├── README.md │ ├── __tests__ │ │ ├── dialog-axe.test.tsx │ │ └── dialog.test.tsx │ ├── package.json │ ├── src │ │ └── reach-dialog.tsx │ ├── styles.css │ ├── tsconfig.json │ └── tsup.config.ts ├── disclosure │ ├── .eslintignore │ ├── CHANGELOG.md │ ├── README.md │ ├── __tests__ │ │ ├── disclosure-axe.test.tsx │ │ └── disclosure.test.tsx │ ├── package.json │ ├── src │ │ └── reach-disclosure.tsx │ ├── tsconfig.json │ └── tsup.config.ts ├── dropdown │ ├── .eslintignore │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ └── reach-dropdown.tsx │ ├── styles.css │ ├── tsconfig.json │ └── tsup.config.ts ├── listbox │ ├── .eslintignore │ ├── CHANGELOG.md │ ├── README.md │ ├── __tests__ │ │ ├── listbox-axe.test.tsx │ │ └── listbox.test.tsx │ ├── package.json │ ├── src │ │ ├── NOTES.md │ │ ├── machine.ts │ │ └── reach-listbox.tsx │ ├── styles.css │ ├── tsconfig.json │ └── tsup.config.ts ├── machine │ ├── .eslintignore │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ └── reach-machine.ts │ ├── tsconfig.json │ └── tsup.config.ts ├── menu-button │ ├── .eslintignore │ ├── CHANGELOG.md │ ├── README.md │ ├── __tests__ │ │ ├── menu-button-axe.test.tsx │ │ └── menu-button.test.tsx │ ├── package.json │ ├── src │ │ └── reach-menu-button.tsx │ ├── styles.css │ ├── tsconfig.json │ └── tsup.config.ts ├── polymorphic │ ├── .eslintignore │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ └── reach-polymorphic.ts │ ├── tsconfig.json │ └── tsup.config.ts ├── popover │ ├── .eslintignore │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ └── reach-popover.tsx │ ├── tsconfig.json │ └── tsup.config.ts ├── portal │ ├── .eslintignore │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ └── reach-portal.tsx │ ├── tsconfig.json │ └── tsup.config.ts ├── rect │ ├── .eslintignore │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ └── reach-rect.tsx │ ├── tsconfig.json │ └── tsup.config.ts ├── skip-nav │ ├── .eslintignore │ ├── CHANGELOG.md │ ├── README.md │ ├── __tests__ │ │ └── skip-nav-axe.test.tsx │ ├── package.json │ ├── src │ │ └── reach-skip-nav.tsx │ ├── styles.css │ ├── tsconfig.json │ └── tsup.config.ts ├── slider │ ├── .eslintignore │ ├── CHANGELOG.md │ ├── README.md │ ├── __tests__ │ │ ├── slider-axe.test.tsx │ │ └── slider.test.tsx │ ├── package.json │ ├── src │ │ └── reach-slider.tsx │ ├── styles.css │ ├── tsconfig.json │ └── tsup.config.ts ├── tabs │ ├── .eslintignore │ ├── CHANGELOG.md │ ├── README.md │ ├── __tests__ │ │ ├── tabs-axe.test.tsx │ │ └── tabs.test.tsx │ ├── package.json │ ├── src │ │ └── reach-tabs.tsx │ ├── styles.css │ ├── tsconfig.json │ └── tsup.config.ts ├── tooltip │ ├── .eslintignore │ ├── CHANGELOG.md │ ├── README.md │ ├── __tests__ │ │ ├── tooltip-axe.test.tsx │ │ └── tooltip.test.tsx │ ├── package.json │ ├── src │ │ └── reach-tooltip.tsx │ ├── styles.css │ ├── tsconfig.json │ └── tsup.config.ts ├── utils │ ├── .eslintignore │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ ├── can-use-dom.ts │ │ ├── clone-valid-element.ts │ │ ├── compose-event-handlers.ts │ │ ├── compose-refs.ts │ │ ├── computed-styles.ts │ │ ├── context.tsx │ │ ├── dev-utils.ts │ │ ├── get-document-dimensions.ts │ │ ├── get-scroll-position.ts │ │ ├── get-scrollbar-offset.ts │ │ ├── is-right-click.ts │ │ ├── make-id.ts │ │ ├── noop.ts │ │ ├── owner-document.ts │ │ ├── reach-utils.ts │ │ ├── type-check.ts │ │ ├── types.ts │ │ ├── use-constant.ts │ │ ├── use-controlled-state.ts │ │ ├── use-event-listener.ts │ │ ├── use-focus-change.ts │ │ ├── use-force-update.ts │ │ ├── use-isomorphic-layout-effect.ts │ │ ├── use-lazy-ref.ts │ │ ├── use-previous.ts │ │ ├── use-stable-callback.ts │ │ ├── use-stateful-ref-value.ts │ │ └── use-update-effect.ts │ ├── tsconfig.json │ └── tsup.config.ts ├── visually-hidden │ ├── .eslintignore │ ├── CHANGELOG.md │ ├── README.md │ ├── __tests__ │ │ ├── visually-hidden-axe.test.tsx │ │ └── visually-hidden.test.tsx │ ├── package.json │ ├── src │ │ └── reach-visually-hidden.tsx │ ├── tsconfig.json │ └── tsup.config.ts └── window-size │ ├── .eslintignore │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ └── reach-window-size.tsx │ ├── tsconfig.json │ └── tsup.config.ts ├── playground ├── .storybook │ ├── main.js │ ├── manager.js │ ├── preview.js │ └── styles.css ├── babel.config.js ├── package.json └── stories │ ├── accordion.story.ts │ ├── accordion │ ├── animated.example.tsx │ ├── basic.example.tsx │ ├── collapsible.example.tsx │ ├── controlled.example.tsx │ ├── multiple-collapsible.example.tsx │ ├── multiple.example.tsx │ ├── read-only.example.tsx │ ├── styled.example.tsx │ ├── with-arbitrary-elements.example.tsx │ ├── with-arrows.example.tsx │ ├── with-index-prop.example.tsx │ └── with-useaccordioncontext-hook.example.tsx │ ├── alert-dialog │ ├── basic-ts.example.tsx │ ├── basic.example.js │ └── index.story.js │ ├── alert.story.ts │ ├── alert │ └── basic.example.tsx │ ├── checkbox │ ├── basic-custom.css │ ├── basic-custom.example.js │ ├── basic-mixed.example.js │ ├── checklist.example.js │ ├── custom-composed.example.js │ ├── custom-group.example.js │ ├── disabled.example.js │ ├── hook.example.tsx │ └── index.story.js │ ├── combobox │ ├── basic.example.tsx │ ├── cities.ts │ ├── controlled.example.tsx │ ├── in-form.example.tsx │ ├── index.story.ts │ ├── lots-of-elements.example.tsx │ ├── no-popover.example.tsx │ ├── open-on-focus.example.tsx │ ├── simulated-change.example.tsx │ ├── token-input.example.tsx │ ├── utils.ts │ ├── with-button.example.tsx │ ├── with-custom-select-data.example.tsx │ └── with-usecomboboxcontext-hook.example.tsx │ ├── dialog.story.ts │ ├── dialog │ ├── animated.example.tsx │ ├── aria-hides-content.example.tsx │ ├── autofocus.example.tsx │ ├── basic.example.tsx │ ├── change-styles.example.tsx │ ├── custom-focus-lock.example.tsx │ ├── custom-portal-node.example.tsx │ ├── destroy-trigger.example.tsx │ ├── dismiss.example.tsx │ ├── dropdown.example.tsx │ ├── long-content.example.tsx │ ├── nested.example.tsx │ ├── no-tabbables.example.tsx │ ├── with-dialog-overlay.example.tsx │ ├── with-tooltip.example.tsx │ └── with-wrapped-components.example.tsx │ ├── disclosure.story.ts │ ├── disclosure │ ├── basic.example.tsx │ └── controlled.example.tsx │ ├── listbox.story.ts │ ├── listbox │ ├── basic.example.tsx │ ├── common.tsx │ ├── composed.example.tsx │ ├── controlled.example.tsx │ ├── dynamic-content.example.tsx │ ├── focus-on-select.example.tsx │ ├── grouped-composed-label.example.tsx │ ├── grouped.example.tsx │ ├── in-form.example.tsx │ ├── position-over-active.example.tsx │ ├── styled.example.tsx │ ├── with-nested-tabbables.example.tsx │ └── with-uselistboxcontext-hook.example.tsx │ ├── menu-button.story.ts │ ├── menu-button │ ├── animate.css │ ├── animated.example.tsx │ ├── basic.example.tsx │ ├── conditional-items.example.tsx │ ├── corners.example.tsx │ ├── custom-wrapper.example.tsx │ ├── focus-on-select.example.tsx │ ├── inside-dialog.example.tsx │ ├── long-text.example.tsx │ ├── no-portal.example.tsx │ ├── non-menu-children.example.tsx │ ├── pete-older.png │ ├── pete-younger.png │ ├── render-prop.example.tsx │ ├── styled.example.tsx │ ├── with-disabled-items.example.tsx │ ├── with-disabled-links.example.tsx │ ├── with-other-tabbables.example.tsx │ ├── with-render-props.example.tsx │ ├── with-styled-router.example.tsx │ ├── with-tooltip.example.tsx │ └── with-usemenubuttoncontext-hook.example.tsx │ ├── popover.story.ts │ ├── popover │ ├── basic.example.tsx │ └── hidden.example.tsx │ ├── portal.story.ts │ ├── portal │ └── basic.example.tsx │ ├── rect.story.js │ ├── rect │ ├── basic-use-rect.example.tsx │ ├── basic.example.tsx │ ├── change-observed-ref.example.tsx │ ├── pin-use-rect.example.tsx │ └── pin.example.tsx │ ├── skip-nav.story.ts │ ├── skip-nav │ ├── basic.example.tsx │ └── with-custom-id.example.tsx │ ├── slider.story.ts │ ├── slider │ ├── basic.example.tsx │ ├── contained-handle.example.tsx │ ├── controlled-audio-progress.example.tsx │ ├── controlled.example.tsx │ ├── examples.css │ ├── utils.ts │ ├── vertical.example.tsx │ ├── with-form.example.tsx │ ├── with-steps.example.tsx │ └── with-tooltip.example.tsx │ ├── tabs.story.ts │ ├── tabs │ ├── animated-bar.example.tsx │ ├── basic-strict-mode.example.tsx │ ├── basic.example.tsx │ ├── controlled.example.tsx │ ├── disabled.example.tsx │ ├── manual-activation.example.tsx │ ├── rtl-direction.example.tsx │ ├── rtl-html.example.tsx │ ├── vertical-rtl.example.tsx │ ├── vertical.example.tsx │ ├── with-arbitrary-elements.example.tsx │ ├── with-render-props.example.tsx │ └── wrappers-wild.example.tsx │ ├── tooltip.story.ts │ ├── tooltip │ ├── animated.example.tsx │ ├── basic.example.tsx │ ├── custom-tooltip.example.tsx │ ├── triangle.example.tsx │ └── with-dialog.example.tsx │ ├── visually-hidden.story.ts │ ├── visually-hidden │ └── basic.example.tsx │ └── window-size │ ├── basic.example.js │ ├── basic.example.tsx │ ├── hook.example.js │ └── index.story.js ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── scripts ├── deploy-website.sh ├── package.json ├── postbuild.js ├── prepublish.js └── utils.js ├── test ├── alias.ts ├── env.ts ├── setupTests.ts ├── types.ts └── utils.tsx ├── tsconfig.json ├── turbo.json ├── vitest.config.ts ├── website-deploy-key.enc └── website ├── docs └── source.json ├── gatsby-browser.js ├── gatsby-config.js ├── gatsby-node.js ├── gatsby-ssr.js ├── package.json ├── postcss.config.js ├── src ├── componentDefs.js ├── components │ ├── AsPropWarning.js │ ├── Layout.js │ ├── Logo.js │ ├── MatchMedia.js │ ├── MdxPre.js │ ├── Note.js │ ├── Note.module.scss │ ├── Pipe.js │ ├── PropTable.js │ ├── SEO.js │ ├── SVG.js │ ├── TOC.js │ ├── Table.js │ ├── cities.js │ ├── createMediaListener.js │ └── mdx-layout.js ├── images │ └── reach-icon.png ├── pages │ ├── 404.js │ ├── accordion.mdx │ ├── alert-dialog.mdx │ ├── alert.mdx │ ├── animation.mdx │ ├── auto-id.mdx │ ├── checkbox.mdx │ ├── combobox.mdx │ ├── dialog.mdx │ ├── disclosure.mdx │ ├── funding.mdx │ ├── index.mdx │ ├── listbox.mdx │ ├── menu-button.mdx │ ├── portal.mdx │ ├── rect.mdx │ ├── skip-nav.mdx │ ├── slider.mdx │ ├── styling.mdx │ ├── tabs.mdx │ ├── tooltip.mdx │ ├── visually-hidden.mdx │ └── window-size.mdx └── styles │ ├── app.scss │ ├── normalize.scss │ ├── root.scss │ ├── skeleton.scss │ └── syntax.scss ├── static └── router │ ├── index.html │ └── static │ └── js │ ├── 0.94cd3f75.chunk.js │ ├── 1.41891795.chunk.js │ ├── 10.c6ce23af.chunk.js │ ├── 11.17ebe0f4.chunk.js │ ├── 12.a70899db.chunk.js │ ├── 13.7442586c.chunk.js │ ├── 14.25b7d9c6.chunk.js │ ├── 15.3d16eb03.chunk.js │ ├── 16.22637d22.chunk.js │ ├── 17.066db434.chunk.js │ ├── 18.ef28657a.chunk.js │ ├── 19.f5b998fa.chunk.js │ ├── 2.0ed88235.chunk.js │ ├── 20.dccd3610.chunk.js │ ├── 21.1e330ea6.chunk.js │ ├── 22.ed80f089.chunk.js │ ├── 23.8a2721fe.chunk.js │ ├── 24.7721e74d.chunk.js │ ├── 25.2c769d79.chunk.js │ ├── 26.f55ae2ec.chunk.js │ ├── 27.0815c9fd.chunk.js │ ├── 28.24e5c604.chunk.js │ ├── 29.d340be96.chunk.js │ ├── 3.ac7d0495.chunk.js │ ├── 30.fd7cb607.chunk.js │ ├── 31.9dc55603.chunk.js │ ├── 32.3ca85418.chunk.js │ ├── 33.375b9bc6.chunk.js │ ├── 34.11446d53.chunk.js │ ├── 35.d36196bd.chunk.js │ ├── 4.83b25e29.chunk.js │ ├── 5.311f1824.chunk.js │ ├── 6.bfe44348.chunk.js │ ├── 7.2c3b2eeb.chunk.js │ ├── 8.ce712278.chunk.js │ ├── 9.e7cbaa3d.chunk.js │ ├── app.f4d1301c.js │ ├── vendor.f4d1301c.js │ ├── vendors~app.6755dc85.chunk.js │ └── vendors~app~vendor.4982872f.chunk.js └── yarn.lock /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@2.0.0/schema.json", 3 | "changelog": ["@remix-run/changelog-github", { "repo": "reach/reach-ui" }], 4 | "commit": false, 5 | "fixed": [ 6 | [ 7 | "@reach/accordion", 8 | "@reach/alert", 9 | "@reach/alert-dialog", 10 | "@reach/auto-id", 11 | "@reach/checkbox", 12 | "@reach/combobox", 13 | "@reach/descendants", 14 | "@reach/dialog", 15 | "@reach/disclosure", 16 | "@reach/dropdown", 17 | "@reach/listbox", 18 | "@reach/machine", 19 | "@reach/menu-button", 20 | "@reach/polymorphic", 21 | "@reach/popover", 22 | "@reach/portal", 23 | "@reach/rect", 24 | "@reach/skip-nav", 25 | "@reach/slider", 26 | "@reach/tabs", 27 | "@reach/tooltip", 28 | "@reach/utils", 29 | "@reach/visually-hidden", 30 | "@reach/window-size" 31 | ] 32 | ], 33 | "linked": [], 34 | "access": "public", 35 | "baseBranch": "dev", 36 | "updateInternalDependencies": "patch", 37 | "ignore": [] 38 | } 39 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = tab 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.yml,*.yaml] 13 | indent_style = space 14 | indent_size = 2 15 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["chance", "chance/react", "chance/typescript"], 3 | "overrides": [ 4 | { 5 | "files": ["*.ts", "*.tsx"], 6 | "rules": { 7 | "@typescript-eslint/consistent-type-imports": [ 8 | "warn", 9 | { 10 | "disallowTypeAnnotations": false 11 | } 12 | ] 13 | } 14 | }, 15 | { 16 | "files": ["*.test.ts", "*.test.tsx"], 17 | "rules": { 18 | "react/display-name": "off" 19 | } 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: reach-ui 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F41B Bug report" 3 | about: Create a report to help make Reach UI better 4 | --- 5 | 6 | ## 🐛 Bug report 7 | 8 | ### Current Behavior 9 | 10 | 11 | 12 | ### Expected behavior 13 | 14 | 15 | 16 | ### Reproducible example 17 | 18 | 19 | 20 | ### Suggested solution(s) 21 | 22 | 23 | 24 | ### Additional context 25 | 26 | 27 | 28 | ### Your environment 29 | 30 | 31 | 32 | | Software | Name(s) | Version | 33 | | ---------------- | ------- | ------- | 34 | | Reach Package | | | 35 | | React | | | 36 | | Browser | | | 37 | | Assistive tech | | | 38 | | Node | | | 39 | | npm/yarn | | | 40 | | Operating System | | | 41 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Documentation.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F41B Documentation" 3 | about: Suggestions for Reach UI documentation 4 | --- 5 | 6 | ## 📖 Documentation 7 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F680Feature request" 3 | about: Suggest an idea for a feature or a new component for Reach UI 4 | --- 5 | 6 | ## 🚀 Feature request 7 | 8 | ### Current Behavior 9 | 10 | 11 | 12 | ### Desired Behavior 13 | 14 | 15 | 16 | ### Suggested Solution 17 | 18 | 19 | 20 | 21 | 22 | ### Who does this impact? Who is this for? 23 | 24 | 25 | 26 | ### Describe alternatives you've considered 27 | 28 | 29 | 30 | ### Additional context 31 | 32 | 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "❓Question" 3 | about: "For usage questions, please use Stack Overflow or Reactiflux!" 4 | --- 5 | 6 | ## ❓Question 7 | 8 | Were are working on getting a dedicated channel on [Reactiflux](https://www.reactiflux.com/), but you can still post questions there under one of the `need-help` or `libraries` channels in the mean time. 9 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Thank you for contributing to Reach UI! Please fill in this template before submitting your PR to help us process your request more quickly. 2 | 3 | - [ ] Use a meaningful title for the pull request. Include the name of the package modified. 4 | - [ ] Test the change in your own code (Compile and run). 5 | - [ ] Add or edit tests to reflect the change (Run with `yarn test`). 6 | - [ ] Add or edit Storybook examples to reflect the change (Run with `yarn start`). 7 | - [ ] Ensure formatting is consistent with the project's Prettier configuration. 8 | - [ ] Add documentation to support any new features. 9 | 10 | This pull request: 11 | 12 | - [ ] Creates a new package 13 | - [ ] Fixes a bug in an existing package 14 | - [ ] Adds additional features/functionality to an existing package 15 | - [ ] Updates documentation or example code 16 | - [ ] Other 17 | 18 | If creating a new package: 19 | 20 | - [ ] Make sure the new package directory contains each of the following, and that their structure/formatting mirrors other related examples in the project: 21 | - [ ] `examples` directory 22 | - [ ] `src` directory with an `index.tsx` entry file 23 | - [ ] At least one example file per feature introduced by the new package 24 | - [ ] Base styles in a `style.css` file (if needed by the new package) 25 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 180 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 14 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - "Status: In Progress" 8 | - "Status: Investigation" 9 | - "Type: Bug" 10 | - "Type: Request for Comment" 11 | - "Type: Regression" 12 | - "Resolution: Won't Fix" 13 | # Label to use when marking an issue as stale 14 | staleLabel: "Resolution: Stale" 15 | # Comment to post when marking an issue as stale. Set to `false` to disable 16 | markComment: false 17 | # Comment to post when closing a stale issue. Set to `false` to disable 18 | closeComment: false 19 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - dev 8 | pull_request: 9 | paths-ignore: 10 | - "playground/**" 11 | - "scripts/**" 12 | - "website/**" 13 | - "**/*.md" 14 | 15 | jobs: 16 | test: 17 | name: Test 18 | if: github.repository == 'reach/reach-ui' 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - name: Checkout 23 | uses: actions/checkout@v3 24 | 25 | - name: Setup Node 26 | uses: actions/setup-node@v3 27 | with: 28 | node-version-file: '.nvmrc' 29 | 30 | - name: Install dependencies 31 | uses: pnpm/action-setup@v2.2.2 32 | with: 33 | version: 7 34 | run_install: | 35 | - recursive: true 36 | args: [--frozen-lockfile, --strict-peer-dependencies] 37 | 38 | - name: Build Packages 39 | run: pnpm build 40 | 41 | - name: Run Tests 42 | run: pnpm test 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.pem 3 | *.log 4 | *.log* 5 | /NOTES.md 6 | /packages/*/dist 7 | /internal/*/dist 8 | .vscode 9 | node_modules 10 | .cache 11 | .turbo 12 | .env 13 | coverage 14 | 15 | # website 16 | /website-deploy-key 17 | /website-deploy-key.pub 18 | /website/public/ 19 | /__git 20 | /test -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | strict-peer-dependencies=false 2 | enable-pre-post-scripts=true 3 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 18 -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | *.yml 2 | node_modules 3 | packages/*/dist 4 | website/static 5 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": true, 3 | "tabWidth": 2 4 | } 5 | -------------------------------------------------------------------------------- /HOUSEKEEPING.md: -------------------------------------------------------------------------------- 1 | # Housekeeping notes 2 | 3 | Clean for now :) 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018-2022, React Training LLC 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /internal/dev/.eslintignore: -------------------------------------------------------------------------------- 1 | dist/ -------------------------------------------------------------------------------- /internal/dev/.gitignore: -------------------------------------------------------------------------------- 1 | /dist 2 | -------------------------------------------------------------------------------- /internal/dev/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@reach-internal/dev", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": {}, 6 | "dependencies": {}, 7 | "devDependencies": { 8 | "@reach-internal/tsconfig": "workspace:*", 9 | "tsup": "^6.1.3" 10 | }, 11 | "peerDependencies": { 12 | "tsup": "^6.1.3" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /internal/dev/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@reach-internal/tsconfig/base.json", 3 | "include": ["."] 4 | } 5 | -------------------------------------------------------------------------------- /internal/dev/tsup.d.ts: -------------------------------------------------------------------------------- 1 | import type { TsupConfig } from "./types"; 2 | 3 | export function getTsupConfig( 4 | entry: string | string[], 5 | args: { 6 | packageName: string; 7 | packageVersion: string; 8 | external?: string[]; 9 | define?: Record; 10 | } 11 | ): TsupConfig; 12 | 13 | export function getPackageInfo(packageRoot: string): { 14 | version: string; 15 | name: string; 16 | }; 17 | -------------------------------------------------------------------------------- /internal/dev/types.ts: -------------------------------------------------------------------------------- 1 | import type { defineConfig } from "tsup"; 2 | 3 | export type TsupConfig = ReturnType; 4 | -------------------------------------------------------------------------------- /internal/test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@reach-internal/test", 3 | "version": "0.0.0", 4 | "private": true 5 | } 6 | -------------------------------------------------------------------------------- /internal/test/types.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | queries, 3 | RenderOptions as TLRenderOptions, 4 | RenderResult as TLRenderResult, 5 | } from "@testing-library/react"; 6 | 7 | export type RenderOptions = Omit & { 8 | strict?: boolean; 9 | }; 10 | 11 | export type RenderResult< 12 | P extends React.HTMLAttributes, 13 | T extends HTMLElement 14 | > = TLRenderResult & { 15 | setProps(props: P): RenderResult; 16 | forceUpdate(): RenderResult; 17 | }; 18 | -------------------------------------------------------------------------------- /internal/tsconfig/README.md: -------------------------------------------------------------------------------- 1 | # `tsconfig` 2 | 3 | These are base shared `tsconfig.json`s from which all other `tsconfig.json`'s inherit from. 4 | -------------------------------------------------------------------------------- /internal/tsconfig/base.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Default", 4 | "compilerOptions": { 5 | "composite": false, 6 | "declaration": true, 7 | "declarationMap": true, 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "inlineSources": false, 12 | "isolatedModules": true, 13 | "moduleResolution": "node", 14 | "noUnusedLocals": false, 15 | "noUnusedParameters": false, 16 | "preserveWatchOutput": true, 17 | "skipLibCheck": true, 18 | "strict": true 19 | }, 20 | "exclude": ["node_modules"] 21 | } 22 | -------------------------------------------------------------------------------- /internal/tsconfig/dom.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "React Library", 4 | "extends": "./base.json", 5 | "compilerOptions": { 6 | "lib": ["ES2022", "DOM", "DOM.Iterable"], 7 | "module": "ESNext", 8 | "target": "ES2015" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /internal/tsconfig/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@reach-internal/tsconfig", 3 | "version": "0.0.0", 4 | "private": true, 5 | "files": [ 6 | "base.json", 7 | "react-library.json" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /internal/tsconfig/react-library.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "React Library", 4 | "extends": "./dom.json", 5 | "compilerOptions": { 6 | "jsx": "react-jsx" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/accordion/.eslintignore: -------------------------------------------------------------------------------- 1 | dist -------------------------------------------------------------------------------- /packages/accordion/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # `@reach/accordion` 2 | 3 | ## 0.18.0 4 | 5 | ### BREAKING Changes 6 | 7 | - All default exports have been removed. Replace all default imports with the appropriate documented named export. 8 | - The output directory structure has changed slightly. Module files are now named `reach-.mjs` instead of `reach-.esm.js`. 9 | 10 | ### Minor Changes 11 | 12 | - We have simplified our build setup to remove a boatload of dependencies. Build output for all packages may look slightly different, though functionally packages that don't have explicit changes marked in the release notes have not changed. 13 | 14 | This may affect you if you use `patch-package` to modify output code. If you need support for legacy browsers, the new bundle may not transpile the same ECMA features as before. In that case you may want to transpile Reach packages directly. 15 | 16 | - We no longer check that our internal styles are included by looking for a defined CSS custom property. You can still include our base styles as before, but this removes the need to define `--reach-` in your own stylesheets to silence dev warnings. 17 | 18 | ### Patch Changes 19 | 20 | - Updated dependencies: 21 | - `@reach/auto-id@0.18.0` 22 | - `@reach/descendants@0.18.0` 23 | - `@reach/utils@0.18.0` 24 | - `@reach/polymorphic@0.18.0` 25 | -------------------------------------------------------------------------------- /packages/accordion/README.md: -------------------------------------------------------------------------------- 1 | # @reach/accordion 2 | 3 | [![Stable release](https://img.shields.io/npm/v/@reach/accordion.svg)](https://npm.im/@reach/accordion) ![MIT license](https://badgen.now.sh/badge/license/MIT) 4 | 5 | [Docs](https://reach.tech/accordion) | [Source](https://github.com/reach/reach-ui/tree/main/packages/accordion) | [WAI-ARIA](https://www.w3.org/TR/wai-aria-practices-1.2/#accordion) 6 | -------------------------------------------------------------------------------- /packages/accordion/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@reach/accordion", 3 | "version": "0.18.0", 4 | "description": "Accessible React accordion component", 5 | "author": "React Training ", 6 | "license": "MIT", 7 | "sideEffects": [ 8 | "*.css" 9 | ], 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/reach/reach-ui.git", 13 | "directory": "packages/accordion" 14 | }, 15 | "scripts": { 16 | "build": "tsup" 17 | }, 18 | "dependencies": { 19 | "@reach/auto-id": "workspace:*", 20 | "@reach/descendants": "workspace:*", 21 | "@reach/polymorphic": "workspace:*", 22 | "@reach/utils": "workspace:*" 23 | }, 24 | "devDependencies": { 25 | "@reach-internal/dev": "workspace:*", 26 | "@reach-internal/test": "workspace:*", 27 | "@reach-internal/tsconfig": "workspace:*", 28 | "react": "^17.0.2", 29 | "react-dom": "^17.0.2", 30 | "tsup": "^6.1.3" 31 | }, 32 | "peerDependencies": { 33 | "react": "^16.8.0 || 17.x", 34 | "react-dom": "^16.8.0 || 17.x" 35 | }, 36 | "main": "./src/reach-accordion.tsx", 37 | "types": "./src/reach-accordion.tsx", 38 | "files": [ 39 | "CHANGELOG.md", 40 | "LICENSE", 41 | "README.md", 42 | "dist", 43 | "styles.css" 44 | ], 45 | "publishConfig": { 46 | "access": "public" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /packages/accordion/styles.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --reach-accordion: 1; 3 | } 4 | 5 | [data-reach-accordion-button][disabled] { 6 | cursor: not-allowed; 7 | } 8 | -------------------------------------------------------------------------------- /packages/accordion/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@reach-internal/tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["node_modules", "dist", "__tests__/**/*", "examples"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/accordion/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import type { defineConfig } from "tsup"; 2 | import { getTsupConfig, getPackageInfo } from "@reach-internal/dev/tsup.js"; 3 | 4 | type TsupConfig = ReturnType; 5 | 6 | let { name: packageName, version: packageVersion } = getPackageInfo( 7 | // @ts-expect-error 8 | __dirname 9 | ); 10 | let cfg: TsupConfig = getTsupConfig(`src/reach-accordion.tsx`, { 11 | packageName, 12 | packageVersion, 13 | }); 14 | export default cfg; 15 | -------------------------------------------------------------------------------- /packages/alert-dialog/.eslintignore: -------------------------------------------------------------------------------- 1 | dist -------------------------------------------------------------------------------- /packages/alert-dialog/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # `@reach/alert-dialog` 2 | 3 | ## 0.18.0 4 | 5 | ### BREAKING Changes 6 | 7 | - All default exports have been removed. Replace all default imports with the appropriate documented named export. 8 | - The output directory structure has changed slightly. Module files are now named `reach-.mjs` instead of `reach-.esm.js`. 9 | 10 | ### Minor Changes 11 | 12 | - We have simplified our build setup to remove a boatload of dependencies. Build output for all packages may look slightly different, though functionally packages that don't have explicit changes marked in the release notes have not changed. 13 | 14 | This may affect you if you use `patch-package` to modify output code. If you need support for legacy browsers, the new bundle may not transpile the same ECMA features as before. In that case you may want to transpile Reach packages directly. 15 | 16 | - We no longer check that our internal styles are included by looking for a defined CSS custom property. You can still include our base styles as before, but this removes the need to define `--reach-` in your own stylesheets to silence dev warnings. 17 | 18 | ### Patch Changes 19 | 20 | - Updated dependencies: 21 | - `@reach/auto-id@0.18.0` 22 | - `@reach/dialog@0.18.0` 23 | - `@reach/utils@0.18.0` 24 | - `@reach/polymorphic@0.18.0` 25 | -------------------------------------------------------------------------------- /packages/alert-dialog/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@reach/alert-dialog", 3 | "version": "0.18.0", 4 | "description": "Accessible React Alert Dialog.", 5 | "author": "React Training ", 6 | "license": "MIT", 7 | "repository": { 8 | "type": "git", 9 | "url": "git+https://github.com/reach/reach-ui.git", 10 | "directory": "packages/alert-dialog" 11 | }, 12 | "scripts": { 13 | "build": "tsup" 14 | }, 15 | "dependencies": { 16 | "@reach/auto-id": "workspace:*", 17 | "@reach/dialog": "workspace:*", 18 | "@reach/polymorphic": "workspace:*", 19 | "@reach/utils": "workspace:*", 20 | "tiny-invariant": "^1.2.0" 21 | }, 22 | "devDependencies": { 23 | "@reach-internal/dev": "workspace:*", 24 | "@reach-internal/test": "workspace:*", 25 | "@reach-internal/tsconfig": "workspace:*", 26 | "react": "^17.0.2", 27 | "react-dom": "^17.0.2", 28 | "tsup": "^6.1.3" 29 | }, 30 | "peerDependencies": { 31 | "react": "^16.8.0 || 17.x", 32 | "react-dom": "^16.8.0 || 17.x" 33 | }, 34 | "main": "./src/reach-alert-dialog.tsx", 35 | "types": "./src/reach-alert-dialog.tsx", 36 | "files": [ 37 | "CHANGELOG.md", 38 | "LICENSE", 39 | "README.md", 40 | "dist" 41 | ], 42 | "publishConfig": { 43 | "access": "public" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /packages/alert-dialog/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@reach-internal/tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["node_modules", "dist", "__tests__", "examples"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/alert-dialog/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import type { defineConfig } from "tsup"; 2 | import { getTsupConfig, getPackageInfo } from "@reach-internal/dev/tsup.js"; 3 | 4 | type TsupConfig = ReturnType; 5 | 6 | let { name: packageName, version: packageVersion } = getPackageInfo( 7 | // @ts-expect-error 8 | __dirname 9 | ); 10 | let cfg: TsupConfig = getTsupConfig("src/reach-alert-dialog.tsx", { 11 | packageName, 12 | packageVersion, 13 | }); 14 | export default cfg; 15 | -------------------------------------------------------------------------------- /packages/alert/.eslintignore: -------------------------------------------------------------------------------- 1 | dist -------------------------------------------------------------------------------- /packages/alert/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # `@reach/alert` 2 | 3 | ## 0.18.0 4 | 5 | ### BREAKING Changes 6 | 7 | - All default exports have been removed. Replace all default imports with the appropriate documented named export. 8 | - The output directory structure has changed slightly. Module files are now named `reach-.mjs` instead of `reach-.esm.js`. 9 | 10 | ### Minor Changes 11 | 12 | - We have simplified our build setup to remove a boatload of dependencies. Build output for all packages may look slightly different, though functionally packages that don't have explicit changes marked in the release notes have not changed. 13 | 14 | This may affect you if you use `patch-package` to modify output code. If you need support for legacy browsers, the new bundle may not transpile the same ECMA features as before. In that case you may want to transpile Reach packages directly. 15 | 16 | ### Patch Changes 17 | 18 | - Hide visual messages from screen reader to prevent double read 19 | - Updated dependencies: 20 | - `@reach/utils@0.18.0` 21 | - `@reach/visually-hidden@0.18.0` 22 | - `@reach/polymorphic@0.18.0` 23 | -------------------------------------------------------------------------------- /packages/alert/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@reach/alert", 3 | "version": "0.18.0", 4 | "description": "Screen-reader-friendly alert messages.", 5 | "author": "React Training ", 6 | "license": "MIT", 7 | "repository": { 8 | "type": "git", 9 | "url": "git+https://github.com/reach/reach-ui.git", 10 | "directory": "packages/alert" 11 | }, 12 | "scripts": { 13 | "build": "tsup" 14 | }, 15 | "dependencies": { 16 | "@reach/polymorphic": "workspace:*", 17 | "@reach/utils": "workspace:*", 18 | "@reach/visually-hidden": "workspace:*" 19 | }, 20 | "devDependencies": { 21 | "@reach-internal/dev": "workspace:*", 22 | "@reach-internal/test": "workspace:*", 23 | "@reach-internal/tsconfig": "workspace:*", 24 | "react": "^17.0.2", 25 | "react-dom": "^17.0.2", 26 | "tsup": "^6.1.3" 27 | }, 28 | "peerDependencies": { 29 | "react": "^16.8.0 || 17.x", 30 | "react-dom": "^16.8.0 || 17.x" 31 | }, 32 | "main": "./src/reach-alert.tsx", 33 | "types": "./src/reach-alert.tsx", 34 | "files": [ 35 | "CHANGELOG.md", 36 | "LICENSE", 37 | "README.md", 38 | "dist" 39 | ], 40 | "publishConfig": { 41 | "access": "public" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /packages/alert/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@reach-internal/tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["node_modules", "dist", "__tests__", "examples"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/alert/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import type { defineConfig } from "tsup"; 2 | import { getTsupConfig, getPackageInfo } from "@reach-internal/dev/tsup.js"; 3 | 4 | type TsupConfig = ReturnType; 5 | 6 | let { name: packageName, version: packageVersion } = getPackageInfo( 7 | // @ts-expect-error 8 | __dirname 9 | ); 10 | let cfg: TsupConfig = getTsupConfig(`src/reach-alert.tsx`, { 11 | packageName, 12 | packageVersion, 13 | }); 14 | export default cfg; 15 | -------------------------------------------------------------------------------- /packages/auto-id/.eslintignore: -------------------------------------------------------------------------------- 1 | dist -------------------------------------------------------------------------------- /packages/auto-id/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # `@reach/auto-id` 2 | 3 | ## 0.18.0 4 | 5 | ### BREAKING Changes 6 | 7 | - All default exports have been removed. Replace all default imports with the appropriate documented named export. 8 | - The output directory structure has changed slightly. Module files are now named `reach-.mjs` instead of `reach-.esm.js`. 9 | 10 | ### Minor Changes 11 | 12 | - We have simplified our build setup to remove a boatload of dependencies. Build output for all packages may look slightly different, though functionally packages that don't have explicit changes marked in the release notes have not changed. 13 | 14 | This may affect you if you use `patch-package` to modify output code. If you need support for legacy browsers, the new bundle may not transpile the same ECMA features as before. In that case you may want to transpile Reach packages directly. 15 | 16 | ### Patch Changes 17 | 18 | - Fix buggy fallback implementation for React 18 ([`f50908c6`](https://github.com/reach/reach-ui/commit/f50908c6203b44032b601307cb5e7b9aece8f4c6)) 19 | - Updated dependencies: 20 | - `@reach/utils@0.18.0` 21 | -------------------------------------------------------------------------------- /packages/auto-id/README.md: -------------------------------------------------------------------------------- 1 | # @reach/auto-id 2 | 3 | [![Stable release](https://img.shields.io/npm/v/@reach/auto-id.svg)](https://npm.im/@reach/auto-id) ![MIT license](https://badgen.now.sh/badge/license/MIT) 4 | 5 | [Docs](https://reach.tech/auto-id) | [Source](https://github.com/reach/reach-ui/tree/main/packages/auto-id) 6 | 7 | Autogenerate IDs to facilitate WAI-ARIA and server rendering. 8 | 9 | A string can be supplied as an argument to be `useId` in lieu of the auto-generated ID. This is handy for accepting user-provided prop IDs that need to be deterministic. 10 | 11 | ```jsx 12 | import { useId } from "@reach/auto-id"; 13 | 14 | function FormField(props) { 15 | const id = useId(props.id); 16 | return ( 17 | 18 | 19 | 20 | 21 | ); 22 | } 23 | ``` 24 | -------------------------------------------------------------------------------- /packages/auto-id/__tests__/auto-id-axe.test.tsx: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | import * as React from "react"; 5 | import { axe } from "vitest-axe"; 6 | import { render, cleanup } from "@reach-internal/test/utils"; 7 | import { vi, it, expect, describe, afterEach } from "vitest"; 8 | 9 | const { useId } = await vi.importActual( 10 | "@reach/auto-id" 11 | ); 12 | 13 | afterEach(cleanup); 14 | 15 | describe("useId with axe", () => { 16 | it("should provide a valid ID for a11y", async () => { 17 | vi.useRealTimers(); 18 | let { container } = render(); 19 | let results = await axe(container); 20 | expect(results).toHaveNoViolations(); 21 | }); 22 | }); 23 | 24 | function TestInput() { 25 | let id = `name--${useId()}`; 26 | return ( 27 |
28 | 29 | 30 |
31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /packages/auto-id/__tests__/auto-id.test.tsx: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | import * as React from "react"; 5 | import { render, cleanup } from "@reach-internal/test/utils"; 6 | import { vi, it, expect, describe, afterEach } from "vitest"; 7 | 8 | const { useId } = await vi.importActual( 9 | "@reach/auto-id" 10 | ); 11 | 12 | afterEach(cleanup); 13 | 14 | describe("useId", () => { 15 | it("should generate a unique ID value", () => { 16 | function Comp() { 17 | let justNull = null; 18 | let randId = useId(justNull); 19 | let randId2 = useId(); 20 | return ( 21 |
22 |
Wow
23 |
Ok
24 |
25 | ); 26 | } 27 | 28 | let { getByText } = render(); 29 | let id1 = Number(getByText("Wow").id); 30 | let id2 = Number(getByText("Ok").id); 31 | expect(id2).not.toEqual(id1); 32 | }); 33 | it("uses a fallback ID", () => { 34 | function Comp() { 35 | let newId = useId("awesome"); 36 | return
Ok
; 37 | } 38 | let { getByText } = render(); 39 | expect(getByText("Ok").id).toEqual("awesome"); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /packages/auto-id/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@reach/auto-id", 3 | "version": "0.18.0", 4 | "description": "Autogenerate IDs to facilitate WAI-ARIA and server rendering.", 5 | "author": "React Training ", 6 | "license": "MIT", 7 | "sideEffects": [ 8 | "*.css" 9 | ], 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/reach/reach-ui.git", 13 | "directory": "packages/auto-id" 14 | }, 15 | "scripts": { 16 | "build": "tsup" 17 | }, 18 | "dependencies": { 19 | "@reach/utils": "workspace:*" 20 | }, 21 | "devDependencies": { 22 | "@reach-internal/dev": "workspace:*", 23 | "@reach-internal/test": "workspace:*", 24 | "@reach-internal/tsconfig": "workspace:*", 25 | "react": "^17.0.2", 26 | "react-dom": "^17.0.2", 27 | "tsup": "^6.1.3" 28 | }, 29 | "peerDependencies": { 30 | "react": "^16.8.0 || 17.x", 31 | "react-dom": "^16.8.0 || 17.x" 32 | }, 33 | "main": "./src/reach-auto-id.ts", 34 | "types": "./src/reach-auto-id.ts", 35 | "files": [ 36 | "CHANGELOG.md", 37 | "LICENSE", 38 | "README.md", 39 | "dist" 40 | ], 41 | "publishConfig": { 42 | "access": "public" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /packages/auto-id/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@reach-internal/tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["node_modules", "dist", "__tests__", "examples"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/auto-id/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import type { defineConfig } from "tsup"; 2 | import { getTsupConfig, getPackageInfo } from "@reach-internal/dev/tsup.js"; 3 | 4 | type TsupConfig = ReturnType; 5 | 6 | let { name: packageName, version: packageVersion } = getPackageInfo( 7 | // @ts-expect-error 8 | __dirname 9 | ); 10 | let cfg: TsupConfig = getTsupConfig("src/reach-auto-id.ts", { 11 | packageName, 12 | packageVersion, 13 | }); 14 | export default cfg; 15 | -------------------------------------------------------------------------------- /packages/checkbox/.eslintignore: -------------------------------------------------------------------------------- 1 | dist -------------------------------------------------------------------------------- /packages/checkbox/README.md: -------------------------------------------------------------------------------- 1 | # @reach/checkbox 2 | 3 | [![Stable release](https://img.shields.io/npm/v/@reach/checkbox.svg)](https://npm.im/@reach/checkbox) ![MIT license](https://badgen.now.sh/badge/license/MIT) 4 | 5 | [Docs](https://reach.tech/checkbox) | [Source](https://github.com/reach/reach-ui/tree/main/packages/checkbox) | [WAI-ARIA](https://www.w3.org/TR/wai-aria-practices-1.2/#checkbox) 6 | 7 | React components to build accessible custom checkboxes with support for indeterminate (mixed) state. 8 | -------------------------------------------------------------------------------- /packages/checkbox/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@reach/checkbox", 3 | "version": "0.18.0", 4 | "description": "Accessible components to build custom, tri-state checkboxes in React.", 5 | "author": "React Training ", 6 | "license": "MIT", 7 | "source": "", 8 | "sideEffects": [ 9 | "*.css" 10 | ], 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/reach/reach-ui.git", 14 | "directory": "packages/checkbox" 15 | }, 16 | "scripts": { 17 | "build": "tsup" 18 | }, 19 | "dependencies": { 20 | "@reach/auto-id": "workspace:*", 21 | "@reach/machine": "workspace:*", 22 | "@reach/polymorphic": "workspace:*", 23 | "@reach/utils": "workspace:*" 24 | }, 25 | "devDependencies": { 26 | "@reach-internal/dev": "workspace:*", 27 | "@reach-internal/test": "workspace:*", 28 | "@reach-internal/tsconfig": "workspace:*", 29 | "react": "^17.0.2", 30 | "react-dom": "^17.0.2", 31 | "tsup": "^6.1.3" 32 | }, 33 | "peerDependencies": { 34 | "react": "^16.8.0 || 17.x", 35 | "react-dom": "^16.8.0 || 17.x" 36 | }, 37 | "main": "./src/reach-checkbox.ts", 38 | "types": "./src/reach-checkbox.ts", 39 | "files": [ 40 | "CHANGELOG.md", 41 | "LICENSE", 42 | "README.md", 43 | "dist", 44 | "styles.css" 45 | ], 46 | "publishConfig": { 47 | "access": "public" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /packages/checkbox/src/reach-checkbox.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Welcome to @reach/checkbox! 3 | * 4 | * Accessible components to build custom, tri-state checkboxes in React. 5 | * 6 | * This package provides two top-level components: 7 | * - MixedCheckbox 8 | * - CustomCheckbox 9 | * 10 | * @see Docs https://reach.tech/checkbox 11 | * @see Source https://github.com/reach/reach-ui/tree/main/packages/checkbox 12 | * @see WAI-ARIA https://www.w3.org/TR/wai-aria-practices-1.2/#checkbox 13 | */ 14 | 15 | export * from "./custom"; 16 | export * from "./mixed"; 17 | -------------------------------------------------------------------------------- /packages/checkbox/styles.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --reach-checkbox: 1; 3 | } 4 | 5 | [data-reach-custom-checkbox-container] { 6 | display: inline-block; 7 | position: relative; 8 | margin-right: 0.75ex; 9 | cursor: default; 10 | width: 0.875rem; 11 | height: 0.875rem; 12 | } 13 | 14 | [data-reach-custom-checkbox-container]:focus-within, 15 | [data-reach-custom-checkbox-container][data-focus] { 16 | box-shadow: 0 0 4px 1px Highlight; 17 | outline: -webkit-focus-ring-color auto 4px; 18 | } 19 | 20 | [data-reach-custom-checkbox-input] { 21 | position: absolute !important; 22 | top: 0 !important; 23 | left: 0 !important; 24 | margin: 0 !important; 25 | padding: 0 !important; 26 | width: 100% !important; 27 | height: 100% !important; 28 | opacity: 0 !important; 29 | z-index: 1 !important; 30 | cursor: inherit; 31 | box-shadow: none !important; 32 | outline: none !important; 33 | } 34 | -------------------------------------------------------------------------------- /packages/checkbox/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@reach-internal/tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["node_modules", "dist", "__tests__", "examples"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/checkbox/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import type { defineConfig } from "tsup"; 2 | import { getTsupConfig, getPackageInfo } from "@reach-internal/dev/tsup.js"; 3 | 4 | type TsupConfig = ReturnType; 5 | 6 | let { name: packageName, version: packageVersion } = getPackageInfo( 7 | // @ts-expect-error 8 | __dirname 9 | ); 10 | let cfg: TsupConfig = getTsupConfig("src/reach-checkbox.ts", { 11 | packageName, 12 | packageVersion, 13 | }); 14 | export default cfg; 15 | -------------------------------------------------------------------------------- /packages/combobox/.eslintignore: -------------------------------------------------------------------------------- 1 | dist -------------------------------------------------------------------------------- /packages/combobox/__tests__/latinize.d.ts: -------------------------------------------------------------------------------- 1 | declare module "latinize" { 2 | export default function latinize(string: string): string; 3 | } 4 | -------------------------------------------------------------------------------- /packages/combobox/styles.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --reach-combobox: 1; 3 | } 4 | 5 | [data-reach-combobox-popover] { 6 | border: solid 1px hsla(0, 0%, 0%, 0.25); 7 | background: hsla(0, 100%, 100%, 0.99); 8 | font-size: 85%; 9 | } 10 | 11 | [data-reach-combobox-list] { 12 | list-style: none; 13 | margin: 0; 14 | padding: 0; 15 | user-select: none; 16 | } 17 | 18 | [data-reach-combobox-option] { 19 | cursor: pointer; 20 | margin: 0; 21 | padding: 0.25rem 0.5rem; 22 | } 23 | 24 | [data-reach-combobox-option][aria-selected="true"] { 25 | background: hsl(211, 10%, 95%); 26 | } 27 | 28 | [data-reach-combobox-option]:hover { 29 | background: hsl(211, 10%, 92%); 30 | } 31 | 32 | [data-reach-combobox-option][aria-selected="true"]:hover { 33 | background: hsl(211, 10%, 90%); 34 | } 35 | 36 | [data-suggested-value] { 37 | font-weight: bold; 38 | } 39 | -------------------------------------------------------------------------------- /packages/combobox/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@reach-internal/tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["node_modules", "dist", "__tests__", "examples"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/combobox/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import type { defineConfig } from "tsup"; 2 | import { getTsupConfig, getPackageInfo } from "@reach-internal/dev/tsup.js"; 3 | 4 | type TsupConfig = ReturnType; 5 | 6 | let { name: packageName, version: packageVersion } = getPackageInfo( 7 | // @ts-expect-error 8 | __dirname 9 | ); 10 | let cfg: TsupConfig = getTsupConfig(`src/reach-combobox.tsx`, { 11 | packageName, 12 | packageVersion, 13 | }); 14 | export default cfg; 15 | -------------------------------------------------------------------------------- /packages/descendants/.eslintignore: -------------------------------------------------------------------------------- 1 | dist -------------------------------------------------------------------------------- /packages/descendants/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # `@reach/descendants` 2 | 3 | ## 0.18.0 4 | 5 | ### BREAKING Changes 6 | 7 | - All default exports have been removed. Replace all default imports with the appropriate documented named export. 8 | - The output directory structure has changed slightly. Module files are now named `reach-.mjs` instead of `reach-.esm.js`. 9 | 10 | ### Minor Changes 11 | 12 | - We have simplified our build setup to remove a boatload of dependencies. Build output for all packages may look slightly different, though functionally packages that don't have explicit changes marked in the release notes have not changed. 13 | 14 | This may affect you if you use `patch-package` to modify output code. If you need support for legacy browsers, the new bundle may not transpile the same ECMA features as before. In that case you may want to transpile Reach packages directly. 15 | 16 | ### Patch Changes 17 | 18 | - Fixed a tiny lil index ordering bug ([#827](https://github.com/reach/reach-ui/pull/827)) 19 | - Updated dependencies: 20 | - `@reach/utils@0.18.0` 21 | -------------------------------------------------------------------------------- /packages/descendants/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@reach/descendants", 3 | "version": "0.18.0", 4 | "description": "A descendant index solution for better accessibility support in compound components", 5 | "author": "React Training ", 6 | "license": "MIT", 7 | "repository": { 8 | "type": "git", 9 | "url": "git+https://github.com/reach/reach-ui.git", 10 | "directory": "packages/descendants" 11 | }, 12 | "scripts": { 13 | "build": "tsup" 14 | }, 15 | "dependencies": { 16 | "@reach/utils": "workspace:*" 17 | }, 18 | "devDependencies": { 19 | "@reach-internal/dev": "workspace:*", 20 | "@reach-internal/test": "workspace:*", 21 | "@reach-internal/tsconfig": "workspace:*", 22 | "react": "^17.0.2", 23 | "react-dom": "^17.0.2", 24 | "tsup": "^6.1.3" 25 | }, 26 | "peerDependencies": { 27 | "react": "^16.8.0 || 17.x", 28 | "react-dom": "^16.8.0 || 17.x" 29 | }, 30 | "main": "./src/reach-descendants.tsx", 31 | "types": "./src/reach-descendants.tsx", 32 | "files": [ 33 | "CHANGELOG.md", 34 | "LICENSE", 35 | "README.md", 36 | "dist", 37 | "styles.css" 38 | ], 39 | "publishConfig": { 40 | "access": "public" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /packages/descendants/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@reach-internal/tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["node_modules", "dist", "__tests__", "examples"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/descendants/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import type { defineConfig } from "tsup"; 2 | import { getTsupConfig, getPackageInfo } from "@reach-internal/dev/tsup.js"; 3 | 4 | type TsupConfig = ReturnType; 5 | 6 | let { name: packageName, version: packageVersion } = getPackageInfo( 7 | // @ts-expect-error 8 | __dirname 9 | ); 10 | let cfg: TsupConfig = getTsupConfig(`src/reach-descendants.tsx`, { 11 | packageName, 12 | packageVersion, 13 | }); 14 | export default cfg; 15 | -------------------------------------------------------------------------------- /packages/dialog/.eslintignore: -------------------------------------------------------------------------------- 1 | dist -------------------------------------------------------------------------------- /packages/dialog/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # `@reach/dialog` 2 | 3 | ## 0.18.0 4 | 5 | ### BREAKING Changes 6 | 7 | - All default exports have been removed. Replace all default imports with the appropriate documented named export. 8 | - The output directory structure has changed slightly. Module files are now named `reach-.mjs` instead of `reach-.esm.js`. 9 | 10 | ### Minor Changes 11 | 12 | - We have simplified our build setup to remove a boatload of dependencies. Build output for all packages may look slightly different, though functionally packages that don't have explicit changes marked in the release notes have not changed. 13 | 14 | This may affect you if you use `patch-package` to modify output code. If you need support for legacy browsers, the new bundle may not transpile the same ECMA features as before. In that case you may want to transpile Reach packages directly. 15 | 16 | - We no longer check that our internal styles are included by looking for a defined CSS custom property. You can still include our base styles as before, but this removes the need to define `--reach-` in your own stylesheets to silence dev warnings. 17 | 18 | ### Patch Changes 19 | 20 | - Updated dependencies: 21 | - `@reach/portal@0.18.0` 22 | - `@reach/utils@0.18.0` 23 | - `@reach/polymorphic@0.18.0` 24 | -------------------------------------------------------------------------------- /packages/dialog/README.md: -------------------------------------------------------------------------------- 1 | # @reach/dialog 2 | 3 | [![Stable release](https://img.shields.io/npm/v/@reach/dialog.svg)](https://npm.im/@reach/dialog) ![MIT license](https://badgen.now.sh/badge/license/MIT) 4 | 5 | [Docs](https://reach.tech/dialog) | [Source](https://github.com/reach/reach-ui/tree/main/packages/dialog) | [WAI-ARIA](https://www.w3.org/TR/wai-aria-practices-1.2/#dialog_modal) 6 | 7 | An accessible dialog or modal window. 8 | 9 | ```jsx 10 | import { Dialog } from "@reach/dialog"; 11 | import "@reach/dialog/styles.css"; 12 | 13 | function Example(props) { 14 | const [showDialog, setShowDialog] = React.useState(false); 15 | const open = () => setShowDialog(true); 16 | const close = () => setShowDialog(false); 17 | 18 | return ( 19 |
20 | 21 | 22 | 26 |

Hello there. I am a dialog

27 |
28 |
29 | ); 30 | } 31 | ``` 32 | -------------------------------------------------------------------------------- /packages/dialog/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@reach/dialog", 3 | "version": "0.18.0", 4 | "description": "Accessible React Modal Dialog.", 5 | "author": "React Training ", 6 | "license": "MIT", 7 | "sideEffects": [ 8 | "*.css" 9 | ], 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/reach/reach-ui.git", 13 | "directory": "packages/dialog" 14 | }, 15 | "scripts": { 16 | "build": "tsup" 17 | }, 18 | "dependencies": { 19 | "@reach/polymorphic": "workspace:*", 20 | "@reach/portal": "workspace:*", 21 | "@reach/utils": "workspace:*", 22 | "react-focus-lock": "2.5.2", 23 | "react-remove-scroll": "2.4.3" 24 | }, 25 | "devDependencies": { 26 | "@reach-internal/dev": "workspace:*", 27 | "@reach-internal/test": "workspace:*", 28 | "@reach-internal/tsconfig": "workspace:*", 29 | "react": "^17.0.2", 30 | "react-dom": "^17.0.2", 31 | "tsup": "^6.1.3" 32 | }, 33 | "peerDependencies": { 34 | "react": "^16.8.0 || 17.x", 35 | "react-dom": "^16.8.0 || 17.x" 36 | }, 37 | "main": "./src/reach-dialog.tsx", 38 | "types": "./src/reach-dialog.tsx", 39 | "files": [ 40 | "CHANGELOG.md", 41 | "LICENSE", 42 | "README.md", 43 | "dist", 44 | "styles.css" 45 | ], 46 | "publishConfig": { 47 | "access": "public" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /packages/dialog/styles.css: -------------------------------------------------------------------------------- 1 | /* This code is subject to LICENSE in root of this repository */ 2 | 3 | /* Used to detect in JavaScript if apps have loaded styles or not. */ 4 | :root { 5 | --reach-dialog: 1; 6 | } 7 | 8 | [data-reach-dialog-overlay] { 9 | background: hsla(0, 0%, 0%, 0.33); 10 | position: fixed; 11 | top: 0; 12 | right: 0; 13 | bottom: 0; 14 | left: 0; 15 | overflow: auto; 16 | } 17 | 18 | [data-reach-dialog-content] { 19 | width: 50vw; 20 | margin: 10vh auto; 21 | background: white; 22 | padding: 2rem; 23 | outline: none; 24 | } 25 | -------------------------------------------------------------------------------- /packages/dialog/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@reach-internal/tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["node_modules", "dist", "__tests__", "examples"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/dialog/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import type { defineConfig } from "tsup"; 2 | import { getTsupConfig, getPackageInfo } from "@reach-internal/dev/tsup.js"; 3 | 4 | type TsupConfig = ReturnType; 5 | 6 | let { name: packageName, version: packageVersion } = getPackageInfo( 7 | // @ts-expect-error 8 | __dirname 9 | ); 10 | let cfg: TsupConfig = getTsupConfig(`src/reach-dialog.tsx`, { 11 | packageName, 12 | packageVersion, 13 | }); 14 | export default cfg; 15 | -------------------------------------------------------------------------------- /packages/disclosure/.eslintignore: -------------------------------------------------------------------------------- 1 | dist -------------------------------------------------------------------------------- /packages/disclosure/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # `@reach/disclosure` 2 | 3 | ## 0.18.0 4 | 5 | ### BREAKING Changes 6 | 7 | - All default exports have been removed. Replace all default imports with the appropriate documented named export. 8 | - The output directory structure has changed slightly. Module files are now named `reach-.mjs` instead of `reach-.esm.js`. 9 | 10 | ### Minor Changes 11 | 12 | - We have simplified our build setup to remove a boatload of dependencies. Build output for all packages may look slightly different, though functionally packages that don't have explicit changes marked in the release notes have not changed. 13 | 14 | This may affect you if you use `patch-package` to modify output code. If you need support for legacy browsers, the new bundle may not transpile the same ECMA features as before. In that case you may want to transpile Reach packages directly. 15 | 16 | - We no longer check that our internal styles are included by looking for a defined CSS custom property. You can still include our base styles as before, but this removes the need to define `--reach-` in your own stylesheets to silence dev warnings. 17 | 18 | ### Patch Changes 19 | 20 | - Updated dependencies: 21 | - `@reach/auto-id@0.18.0` 22 | - `@reach/utils@0.18.0` 23 | - `@reach/polymorphic@0.18.0` 24 | -------------------------------------------------------------------------------- /packages/disclosure/README.md: -------------------------------------------------------------------------------- 1 | # @reach/disclosure 2 | 3 | [![Stable release](https://img.shields.io/npm/v/@reach/disclosure.svg)](https://npm.im/@reach/disclosure) ![MIT license](https://badgen.now.sh/badge/license/MIT) 4 | 5 | [Docs](https://reach.tech/disclosure) | [Source](https://github.com/reach/reach-ui/tree/main/packages/disclosure) | [WAI-ARIA](https://www.w3.org/TR/wai-aria-practices-1.2/#disclosure) 6 | -------------------------------------------------------------------------------- /packages/disclosure/__tests__/disclosure-axe.test.tsx: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | import * as React from "react"; 5 | import { cleanup, render, act, fireEvent } from "@reach-internal/test/utils"; 6 | import { axe } from "vitest-axe"; 7 | import { 8 | Disclosure, 9 | DisclosureButton, 10 | DisclosurePanel, 11 | } from "@reach/disclosure"; 12 | import { afterEach, describe, expect, it, vi } from "vitest"; 13 | 14 | afterEach(cleanup); 15 | 16 | describe(" with axe", () => { 17 | it("Should not have ARIA violations", async () => { 18 | vi.useRealTimers(); 19 | let { getByRole, container } = render( 20 | 21 | Click Button 22 | Panel body 23 | 24 | ); 25 | let results = await axe(container); 26 | expect(results).toHaveNoViolations(); 27 | 28 | act(() => void fireEvent.click(getByRole("button"))); 29 | let newResults = await axe(container); 30 | expect(newResults).toHaveNoViolations(); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /packages/disclosure/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@reach/disclosure", 3 | "version": "0.18.0", 4 | "description": "Accessible React disclosure component", 5 | "author": "React Training ", 6 | "license": "MIT", 7 | "repository": { 8 | "type": "git", 9 | "url": "git+https://github.com/reach/reach-ui.git", 10 | "directory": "packages/disclosure" 11 | }, 12 | "scripts": { 13 | "build": "tsup" 14 | }, 15 | "dependencies": { 16 | "@reach/auto-id": "workspace:*", 17 | "@reach/polymorphic": "workspace:*", 18 | "@reach/utils": "workspace:*" 19 | }, 20 | "devDependencies": { 21 | "@reach-internal/dev": "workspace:*", 22 | "@reach-internal/test": "workspace:*", 23 | "@reach-internal/tsconfig": "workspace:*", 24 | "react": "^17.0.2", 25 | "react-dom": "^17.0.2", 26 | "tsup": "^6.1.3" 27 | }, 28 | "peerDependencies": { 29 | "react": "^16.8.0 || 17.x", 30 | "react-dom": "^16.8.0 || 17.x" 31 | }, 32 | "main": "./src/reach-disclosure.tsx", 33 | "types": "./src/reach-disclosure.tsx", 34 | "files": [ 35 | "CHANGELOG.md", 36 | "LICENSE", 37 | "README.md", 38 | "dist" 39 | ], 40 | "publishConfig": { 41 | "access": "public" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /packages/disclosure/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@reach-internal/tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["node_modules", "dist", "__tests__", "examples"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/disclosure/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import type { defineConfig } from "tsup"; 2 | import { getTsupConfig, getPackageInfo } from "@reach-internal/dev/tsup.js"; 3 | 4 | type TsupConfig = ReturnType; 5 | 6 | let { name: packageName, version: packageVersion } = getPackageInfo( 7 | // @ts-expect-error 8 | __dirname 9 | ); 10 | let cfg: TsupConfig = getTsupConfig(`src/reach-disclosure.tsx`, { 11 | packageName, 12 | packageVersion, 13 | }); 14 | export default cfg; 15 | -------------------------------------------------------------------------------- /packages/dropdown/.eslintignore: -------------------------------------------------------------------------------- 1 | dist -------------------------------------------------------------------------------- /packages/dropdown/README.md: -------------------------------------------------------------------------------- 1 | # @reach/dropdown 2 | 3 | [![Stable release](https://img.shields.io/npm/v/@reach/dropdown.svg)](https://npm.im/@reach/dropdown) ![MIT license](https://badgen.now.sh/badge/license/MIT) 4 | 5 | A React dropdown menu. 6 | 7 | **Important:** This package is primarily intended for internal use by the Reach UI library. You should probably not use it directly in your production projects, as the APIs can still change with minor version bumps. You have been warned! 8 | -------------------------------------------------------------------------------- /packages/dropdown/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@reach/dropdown", 3 | "version": "0.18.0", 4 | "description": "React dropdown menu.", 5 | "author": "React Training ", 6 | "license": "MIT", 7 | "sideEffects": [ 8 | "*.css" 9 | ], 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/reach/reach-ui.git", 13 | "directory": "packages/dropdown" 14 | }, 15 | "scripts": { 16 | "build": "tsup" 17 | }, 18 | "dependencies": { 19 | "@reach/auto-id": "workspace:*", 20 | "@reach/descendants": "workspace:*", 21 | "@reach/polymorphic": "workspace:*", 22 | "@reach/popover": "workspace:*", 23 | "@reach/utils": "workspace:*" 24 | }, 25 | "devDependencies": { 26 | "@reach-internal/dev": "workspace:*", 27 | "@reach-internal/test": "workspace:*", 28 | "@reach-internal/tsconfig": "workspace:*", 29 | "react": "^17.0.2", 30 | "react-dom": "^17.0.2", 31 | "tsup": "^6.1.3" 32 | }, 33 | "peerDependencies": { 34 | "react": "^16.8.0 || 17.x", 35 | "react-dom": "^16.8.0 || 17.x" 36 | }, 37 | "main": "./src/reach-dropdown.tsx", 38 | "types": "./src/reach-dropdown.tsx", 39 | "files": [ 40 | "CHANGELOG.md", 41 | "LICENSE", 42 | "README.md", 43 | "dist", 44 | "styles.css" 45 | ], 46 | "publishConfig": { 47 | "access": "public" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /packages/dropdown/styles.css: -------------------------------------------------------------------------------- 1 | [data-reach-dropdown-popover] { 2 | display: block; 3 | position: absolute; 4 | } 5 | 6 | [data-reach-dropdown-popover][hidden] { 7 | display: none; 8 | } 9 | 10 | [data-reach-dropdown-items] { 11 | display: block; 12 | white-space: nowrap; 13 | border: solid 1px hsla(0, 0%, 0%, 0.25); 14 | background: hsla(0, 100%, 100%, 1); 15 | } 16 | 17 | [data-reach-dropdown-item] { 18 | display: block; 19 | user-select: none; 20 | } 21 | 22 | [data-reach-dropdown-item] { 23 | cursor: pointer; 24 | padding: 5px 20px; 25 | } 26 | 27 | [data-reach-dropdown-item][data-selected] { 28 | background: hsla(211, 81%, 36%, 1); 29 | color: hsla(0, 100%, 100%, 1); 30 | outline: none; 31 | } 32 | 33 | [data-reach-dropdown-item][data-disabled] { 34 | opacity: 0.5; 35 | cursor: not-allowed; 36 | } 37 | -------------------------------------------------------------------------------- /packages/dropdown/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@reach-internal/tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["node_modules", "dist", "__tests__", "examples"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/dropdown/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import type { defineConfig } from "tsup"; 2 | import { getTsupConfig, getPackageInfo } from "@reach-internal/dev/tsup.js"; 3 | 4 | type TsupConfig = ReturnType; 5 | 6 | let { name: packageName, version: packageVersion } = getPackageInfo(__dirname); 7 | let cfg: TsupConfig = getTsupConfig(`src/reach-dropdown.tsx`, { 8 | packageName, 9 | packageVersion, 10 | }); 11 | export default cfg; 12 | -------------------------------------------------------------------------------- /packages/listbox/.eslintignore: -------------------------------------------------------------------------------- 1 | dist -------------------------------------------------------------------------------- /packages/listbox/README.md: -------------------------------------------------------------------------------- 1 | # @reach/listbox 2 | 3 | [![Stable release](https://img.shields.io/npm/v/@reach/listbox.svg)](https://npm.im/@reach/listbox) ![MIT license](https://badgen.now.sh/badge/license/MIT) 4 | 5 | [Docs](https://reach.tech/listbox) | [Source](https://github.com/reach/reach-ui/tree/main/packages/listbox) | [WAI-ARIA](https://www.w3.org/TR/wai-aria-practices-1.2/#Listbox) 6 | 7 | An accessible listbox for custom select inputs. 8 | 9 | ```jsx 10 | import * as React from "react"; 11 | import { Listbox, ListboxOption } from "@reach/listbox"; 12 | import "@reach/listbox/styles.css"; 13 | 14 | function Example(props) { 15 | let [value, setValue] = React.useState("default"); 16 | return ( 17 | setValue(value)}> 18 | 🌮 Choose a taco 19 |
20 | 21 | 🌮 Carne Asada 22 | 23 | 24 | 🌮 Pollo 25 | 26 | 27 | 🌮 Pastor 28 | 29 | 30 | 🌮 Lengua 31 | 32 |
33 | ); 34 | } 35 | ``` 36 | -------------------------------------------------------------------------------- /packages/listbox/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@reach-internal/tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["node_modules", "dist", "__tests__", "examples"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/listbox/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import type { defineConfig } from "tsup"; 2 | import { getTsupConfig, getPackageInfo } from "@reach-internal/dev/tsup.js"; 3 | 4 | type TsupConfig = ReturnType; 5 | 6 | let { name: packageName, version: packageVersion } = getPackageInfo( 7 | // @ts-expect-error 8 | __dirname 9 | ); 10 | let cfg: TsupConfig = getTsupConfig(`src/reach-listbox.tsx`, { 11 | packageName, 12 | packageVersion, 13 | }); 14 | export default cfg; 15 | -------------------------------------------------------------------------------- /packages/machine/.eslintignore: -------------------------------------------------------------------------------- 1 | dist -------------------------------------------------------------------------------- /packages/machine/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # `@reach/machine` 2 | 3 | ## 0.18.0 4 | 5 | ### BREAKING Changes 6 | 7 | - All default exports have been removed. Replace all default imports with the appropriate documented named export. 8 | - The output directory structure has changed slightly. Module files are now named `reach-.mjs` instead of `reach-.esm.js`. 9 | 10 | ### Minor Changes 11 | 12 | - We have simplified our build setup to remove a boatload of dependencies. Build output for all packages may look slightly different, though functionally packages that don't have explicit changes marked in the release notes have not changed. 13 | 14 | This may affect you if you use `patch-package` to modify output code. If you need support for legacy browsers, the new bundle may not transpile the same ECMA features as before. In that case you may want to transpile Reach packages directly. 15 | 16 | ### Patch Changes 17 | 18 | - Updated dependencies: 19 | - `@reach/utils@0.18.0` 20 | -------------------------------------------------------------------------------- /packages/machine/README.md: -------------------------------------------------------------------------------- 1 | # @reach/machine 2 | 3 | [![Stable release](https://img.shields.io/npm/v/@reach/machine.svg)](https://npm.im/@reach/machine) ![MIT license](https://badgen.now.sh/badge/license/MIT) 4 | 5 | State machine utilities for the Reach UI library. 6 | 7 | **Important:** This package is intended for internal use by the Reach UI library. You should not use it directly in your production projects, as the APIs can and will change often without regard to semver. You have been warned! 8 | -------------------------------------------------------------------------------- /packages/machine/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@reach/machine", 3 | "version": "0.18.0", 4 | "description": "State machine utilities for the Reach UI library.", 5 | "author": "React Training ", 6 | "license": "MIT", 7 | "sideEffects": [ 8 | "*.css" 9 | ], 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/reach/reach-ui.git", 13 | "directory": "packages/machine" 14 | }, 15 | "scripts": { 16 | "build": "tsup" 17 | }, 18 | "dependencies": { 19 | "@reach/utils": "workspace:*", 20 | "@xstate/fsm": "1.4.0" 21 | }, 22 | "devDependencies": { 23 | "@reach-internal/dev": "workspace:*", 24 | "@reach-internal/test": "workspace:*", 25 | "@reach-internal/tsconfig": "workspace:*", 26 | "react": "^17.0.2", 27 | "react-dom": "^17.0.2", 28 | "tsup": "^6.1.3" 29 | }, 30 | "peerDependencies": { 31 | "react": "^16.8.0 || 17.x", 32 | "react-dom": "^16.8.0 || 17.x" 33 | }, 34 | "main": "./src/reach-machine.ts", 35 | "types": "./src/reach-machine.ts", 36 | "files": [ 37 | "CHANGELOG.md", 38 | "LICENSE", 39 | "README.md", 40 | "dist" 41 | ], 42 | "publishConfig": { 43 | "access": "public" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /packages/machine/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@reach-internal/tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["node_modules", "dist", "__tests__", "examples"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/machine/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import type { defineConfig } from "tsup"; 2 | import { getTsupConfig, getPackageInfo } from "@reach-internal/dev/tsup.js"; 3 | 4 | type TsupConfig = ReturnType; 5 | 6 | let { name: packageName, version: packageVersion } = getPackageInfo( 7 | // @ts-expect-error 8 | __dirname 9 | ); 10 | let cfg: TsupConfig = getTsupConfig(`src/reach-machine.ts`, { 11 | packageName, 12 | packageVersion, 13 | }); 14 | export default cfg; 15 | -------------------------------------------------------------------------------- /packages/menu-button/.eslintignore: -------------------------------------------------------------------------------- 1 | dist -------------------------------------------------------------------------------- /packages/menu-button/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@reach-internal/tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["node_modules", "dist", "__tests__", "examples"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/menu-button/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import type { defineConfig } from "tsup"; 2 | import { getTsupConfig, getPackageInfo } from "@reach-internal/dev/tsup.js"; 3 | 4 | type TsupConfig = ReturnType; 5 | 6 | let { name: packageName, version: packageVersion } = getPackageInfo(__dirname); 7 | let cfg: TsupConfig = getTsupConfig("src/reach-menu-button.tsx", { 8 | packageName, 9 | packageVersion, 10 | }); 11 | export default cfg; 12 | -------------------------------------------------------------------------------- /packages/polymorphic/.eslintignore: -------------------------------------------------------------------------------- 1 | dist -------------------------------------------------------------------------------- /packages/polymorphic/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # `@reach/polymorphic` 2 | 3 | ## 0.18.0 4 | 5 | Initial release. 6 | -------------------------------------------------------------------------------- /packages/polymorphic/README.md: -------------------------------------------------------------------------------- 1 | # @reach/polymorphic 2 | 3 | [![Stable release](https://img.shields.io/npm/v/@reach/polymorphic.svg)](https://npm.im/@reach/polymorphic) ![MIT license](https://badgen.now.sh/badge/license/MIT) 4 | 5 | **Important:** This package is primarily intended for internal use by the Reach UI library. You should not use it directly in your production projects, as the APIs can change at any time without regard to semver. 6 | -------------------------------------------------------------------------------- /packages/polymorphic/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@reach/polymorphic", 3 | "version": "0.18.0", 4 | "description": "Internal utility types for polymorphism in Reach UI.", 5 | "author": "React Training ", 6 | "license": "MIT", 7 | "repository": { 8 | "type": "git", 9 | "url": "git+https://github.com/reach/reach-ui.git", 10 | "directory": "packages/polymorphic" 11 | }, 12 | "scripts": { 13 | "build": "tsup" 14 | }, 15 | "dependencies": {}, 16 | "devDependencies": { 17 | "@reach-internal/dev": "workspace:*", 18 | "@reach-internal/tsconfig": "workspace:*", 19 | "react": "^17.0.2", 20 | "tsup": "^6.1.3" 21 | }, 22 | "peerDependencies": { 23 | "react": "^16.8.0 || 17.x" 24 | }, 25 | "main": "./src/reach-polymorphic.ts", 26 | "types": "./src/reach-polymorphic.ts", 27 | "files": [ 28 | "CHANGELOG.md", 29 | "LICENSE", 30 | "README.md", 31 | "dist" 32 | ], 33 | "publishConfig": { 34 | "access": "public" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/polymorphic/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@reach-internal/tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["node_modules", "dist", "__tests__", "examples"], 5 | "compilerOptions": { 6 | "stripInternal": true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/polymorphic/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import type { defineConfig } from "tsup"; 2 | import { getTsupConfig, getPackageInfo } from "@reach-internal/dev/tsup.js"; 3 | 4 | type TsupConfig = ReturnType; 5 | 6 | let { name: packageName, version: packageVersion } = getPackageInfo( 7 | // @ts-expect-error 8 | __dirname 9 | ); 10 | let cfg: TsupConfig = getTsupConfig(`src/reach-polymorphic.ts`, { 11 | packageName, 12 | packageVersion, 13 | }); 14 | export default cfg; 15 | -------------------------------------------------------------------------------- /packages/popover/.eslintignore: -------------------------------------------------------------------------------- 1 | dist -------------------------------------------------------------------------------- /packages/popover/README.md: -------------------------------------------------------------------------------- 1 | # @reach/popover 2 | 3 | [![Stable release](https://img.shields.io/npm/v/@reach/popover.svg)](https://npm.im/@reach/popover) ![MIT license](https://badgen.now.sh/badge/license/MIT) 4 | 5 | ```jsx 6 | import * as React from "react"; 7 | import { Popover, positionDefault } from "@reach/popover"; 8 | 9 | function Example() { 10 | const ref = React.useRef(null); 11 | const [value, setValue] = React.useState(""); 12 | return ( 13 |
14 | 22 | 23 | {value.length > 0 && ( 24 | 25 |
26 |

Whoa! Look at me!

27 |
28 |
29 | )} 30 |
31 | ); 32 | } 33 | ``` 34 | -------------------------------------------------------------------------------- /packages/popover/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@reach/popover", 3 | "version": "0.18.0", 4 | "description": "Render a portal positioned relative to another element.", 5 | "author": "React Training ", 6 | "license": "MIT", 7 | "scripts": { 8 | "build": "tsup" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/reach/reach-ui.git", 13 | "directory": "packages/popover" 14 | }, 15 | "dependencies": { 16 | "@reach/polymorphic": "workspace:*", 17 | "@reach/portal": "workspace:*", 18 | "@reach/rect": "workspace:*", 19 | "@reach/utils": "workspace:*", 20 | "tabbable": "^5.3.3" 21 | }, 22 | "devDependencies": { 23 | "@reach-internal/dev": "workspace:*", 24 | "@reach-internal/test": "workspace:*", 25 | "@reach-internal/tsconfig": "workspace:*", 26 | "react": "^17.0.2", 27 | "react-dom": "^17.0.2", 28 | "tsup": "^6.1.3" 29 | }, 30 | "peerDependencies": { 31 | "react": "^16.8.0 || 17.x", 32 | "react-dom": "^16.8.0 || 17.x" 33 | }, 34 | "main": "./src/reach-popover.tsx", 35 | "types": "./src/reach-popover.tsx", 36 | "files": [ 37 | "CHANGELOG.md", 38 | "LICENSE", 39 | "README.md", 40 | "dist", 41 | "styles.css" 42 | ] 43 | } 44 | -------------------------------------------------------------------------------- /packages/popover/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@reach-internal/tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["node_modules", "dist", "__tests__", "examples"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/popover/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import type { defineConfig } from "tsup"; 2 | import { getTsupConfig, getPackageInfo } from "@reach-internal/dev/tsup.js"; 3 | 4 | type TsupConfig = ReturnType; 5 | 6 | let { name: packageName, version: packageVersion } = getPackageInfo( 7 | // @ts-expect-error 8 | __dirname 9 | ); 10 | let cfg: TsupConfig = getTsupConfig(`src/reach-popover.tsx`, { 11 | packageName, 12 | packageVersion, 13 | }); 14 | export default cfg; 15 | -------------------------------------------------------------------------------- /packages/portal/.eslintignore: -------------------------------------------------------------------------------- 1 | dist -------------------------------------------------------------------------------- /packages/portal/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # `@reach/portal` 2 | 3 | ## 0.18.0 4 | 5 | ### BREAKING Changes 6 | 7 | - All default exports have been removed. Replace all default imports with the appropriate documented named export. 8 | - The output directory structure has changed slightly. Module files are now named `reach-.mjs` instead of `reach-.esm.js`. 9 | 10 | ### Minor Changes 11 | 12 | - We have simplified our build setup to remove a boatload of dependencies. Build output for all packages may look slightly different, though functionally packages that don't have explicit changes marked in the release notes have not changed. 13 | 14 | This may affect you if you use `patch-package` to modify output code. If you need support for legacy browsers, the new bundle may not transpile the same ECMA features as before. In that case you may want to transpile Reach packages directly. 15 | 16 | ### Patch Changes 17 | 18 | - Updated dependencies: 19 | - `@reach/utils@0.18.0` 20 | -------------------------------------------------------------------------------- /packages/portal/README.md: -------------------------------------------------------------------------------- 1 | # @reach/portal 2 | 3 | [![Stable release](https://img.shields.io/npm/v/@reach/portal.svg)](https://npm.im/@reach/portal) ![MIT license](https://badgen.now.sh/badge/license/MIT) 4 | 5 | [Docs](https://reach.tech/portal) | [Source](https://github.com/reach/reach-ui/tree/main/packages/portal) 6 | 7 | Creates and appends a DOM node to the end of `document.body` and renders a React tree into it. Useful for rendering a natural React element hierarchy with a different DOM hierarchy to prevent parent styles from clipping or hiding content (for popovers, dropdowns, and modals). 8 | 9 | ```jsx 10 | import { Portal } from "@reach/portal"; 11 | 12 | function Example() { 13 | return ( 14 | 15 |
Stuff goes here
16 |
17 | ); 18 | } 19 | ``` 20 | -------------------------------------------------------------------------------- /packages/portal/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@reach/portal", 3 | "version": "0.18.0", 4 | "description": "Declarative portals for React", 5 | "author": "React Training ", 6 | "license": "MIT", 7 | "sideEffects": [ 8 | "*.css" 9 | ], 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/reach/reach-ui.git", 13 | "directory": "packages/portal" 14 | }, 15 | "scripts": { 16 | "build": "tsup" 17 | }, 18 | "dependencies": { 19 | "@reach/utils": "workspace:*" 20 | }, 21 | "devDependencies": { 22 | "@reach-internal/dev": "workspace:*", 23 | "@reach-internal/test": "workspace:*", 24 | "@reach-internal/tsconfig": "workspace:*", 25 | "react": "^17.0.2", 26 | "react-dom": "^17.0.2", 27 | "tsup": "^6.1.3" 28 | }, 29 | "peerDependencies": { 30 | "react": "^16.8.0 || 17.x", 31 | "react-dom": "^16.8.0 || 17.x" 32 | }, 33 | "main": "./src/reach-portal.tsx", 34 | "types": "./src/reach-portal.tsx", 35 | "files": [ 36 | "CHANGELOG.md", 37 | "LICENSE", 38 | "README.md", 39 | "dist", 40 | "styles.css" 41 | ], 42 | "publishConfig": { 43 | "access": "public" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /packages/portal/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@reach-internal/tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["node_modules", "dist", "__tests__", "examples"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/portal/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import type { defineConfig } from "tsup"; 2 | import { getTsupConfig, getPackageInfo } from "@reach-internal/dev/tsup.js"; 3 | 4 | type TsupConfig = ReturnType; 5 | 6 | let { name: packageName, version: packageVersion } = getPackageInfo( 7 | // @ts-expect-error 8 | __dirname 9 | ); 10 | let cfg: TsupConfig = getTsupConfig(`src/reach-portal.tsx`, { 11 | packageName, 12 | packageVersion, 13 | }); 14 | export default cfg; 15 | -------------------------------------------------------------------------------- /packages/rect/.eslintignore: -------------------------------------------------------------------------------- 1 | dist -------------------------------------------------------------------------------- /packages/rect/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # `@reach/rect` 2 | 3 | ## 0.18.0 4 | 5 | ### BREAKING Changes 6 | 7 | - All default exports have been removed. Replace all default imports with the appropriate documented named export. 8 | - The output directory structure has changed slightly. Module files are now named `reach-.mjs` instead of `reach-.esm.js`. 9 | 10 | ### Minor Changes 11 | 12 | - We have simplified our build setup to remove a boatload of dependencies. Build output for all packages may look slightly different, though functionally packages that don't have explicit changes marked in the release notes have not changed. 13 | 14 | This may affect you if you use `patch-package` to modify output code. If you need support for legacy browsers, the new bundle may not transpile the same ECMA features as before. In that case you may want to transpile Reach packages directly. 15 | 16 | ### Patch Changes 17 | 18 | - Updated dependencies: 19 | - `@reach/utils@0.18.0` 20 | -------------------------------------------------------------------------------- /packages/rect/README.md: -------------------------------------------------------------------------------- 1 | # @reach/rect 2 | 3 | [![Stable release](https://img.shields.io/npm/v/@reach/rect.svg)](https://npm.im/@reach/rect) ![MIT license](https://badgen.now.sh/badge/license/MIT) 4 | 5 | [Docs](https://reach.tech/rect) | [Source](https://github.com/reach/reach-ui/tree/main/packages/rect) 6 | 7 | Measures DOM elements (aka. bounding client rect). See also [Element.getBoundingClientRect()](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect) 8 | 9 | ```jsx 10 | import { Rect, useRect } from "@reach/rect"; 11 | 12 | function Example() { 13 | const ref = React.useRef(); 14 | const rect = useRect(ref); 15 | 16 | return ( 17 |
18 |
{JSON.stringify(rect, null, 2)}
19 |
26 |
27 | ); 28 | } 29 | ``` 30 | -------------------------------------------------------------------------------- /packages/rect/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@reach/rect", 3 | "version": "0.18.0", 4 | "description": "Measure React elements position in the DOM", 5 | "author": "React Training ", 6 | "license": "MIT", 7 | "sideEffects": [ 8 | "*.css" 9 | ], 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/reach/reach-ui.git", 13 | "directory": "packages/rect" 14 | }, 15 | "scripts": { 16 | "build": "tsup" 17 | }, 18 | "dependencies": { 19 | "@reach/observe-rect": "1.2.0", 20 | "@reach/utils": "workspace:*" 21 | }, 22 | "devDependencies": { 23 | "@reach-internal/dev": "workspace:*", 24 | "@reach-internal/test": "workspace:*", 25 | "@reach-internal/tsconfig": "workspace:*", 26 | "react": "^17.0.2", 27 | "react-dom": "^17.0.2", 28 | "tsup": "^6.1.3" 29 | }, 30 | "peerDependencies": { 31 | "react": "^16.8.0 || 17.x", 32 | "react-dom": "^16.8.0 || 17.x" 33 | }, 34 | "main": "./src/reach-rect.tsx", 35 | "types": "./src/reach-rect.tsx", 36 | "files": [ 37 | "CHANGELOG.md", 38 | "LICENSE", 39 | "README.md", 40 | "dist" 41 | ], 42 | "publishConfig": { 43 | "access": "public" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /packages/rect/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@reach-internal/tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["node_modules", "dist", "__tests__", "examples"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/rect/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import type { defineConfig } from "tsup"; 2 | import { getTsupConfig, getPackageInfo } from "@reach-internal/dev/tsup.js"; 3 | 4 | type TsupConfig = ReturnType; 5 | 6 | let { name: packageName, version: packageVersion } = getPackageInfo( 7 | // @ts-expect-error 8 | __dirname 9 | ); 10 | let cfg: TsupConfig = getTsupConfig(`src/reach-rect.tsx`, { 11 | packageName, 12 | packageVersion, 13 | }); 14 | export default cfg; 15 | -------------------------------------------------------------------------------- /packages/skip-nav/.eslintignore: -------------------------------------------------------------------------------- 1 | dist -------------------------------------------------------------------------------- /packages/skip-nav/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # `@reach/skip-nav` 2 | 3 | ## 0.18.0 4 | 5 | ### Minor Changes 6 | 7 | ### BREAKING Changes 8 | 9 | - All default exports have been removed. Replace all default imports with the appropriate documented named export. 10 | - The output directory structure has changed slightly. Module files are now named `reach-.mjs` instead of `reach-.esm.js`. 11 | 12 | ### Minor Changes 13 | 14 | - We have simplified our build setup to remove a boatload of dependencies. Build output for all packages may look slightly different, though functionally packages that don't have explicit changes marked in the release notes have not changed. 15 | 16 | This may affect you if you use `patch-package` to modify output code. If you need support for legacy browsers, the new bundle may not transpile the same ECMA features as before. In that case you may want to transpile Reach packages directly. 17 | 18 | - We no longer check that our internal styles are included by looking for a defined CSS custom property. You can still include our base styles as before, but this removes the need to define `--reach-` in your own stylesheets to silence dev warnings. 19 | 20 | ### Patch Changes 21 | 22 | - Updated dependencies: 23 | - `@reach/polymorphic@0.18.0` 24 | -------------------------------------------------------------------------------- /packages/skip-nav/README.md: -------------------------------------------------------------------------------- 1 | # @reach/skip-nav 2 | 3 | [![Stable release](https://img.shields.io/npm/v/@reach/skip-nav.svg)](https://npm.im/@reach/skip-nav) ![MIT license](https://badgen.now.sh/badge/license/MIT) 4 | 5 | [Docs](https://reach.tech/skip-nav) | [Source](https://github.com/reach/reach-ui/tree/main/packages/skip-nav) | [WAI-ARIA](https://webaim.org/techniques/skipnav/) 6 | 7 | Skip navigation link for screen reader and keyboard users. Because the main content is not usually the first thing in the document, it's valuable to provide a shortcut for keyboard and screen reader users to skip to the content. 8 | 9 | If the user does not navigate with the keyboard, they won't see the link. 10 | 11 | ```jsx 12 | import { SkipNavLink, SkipNavContent } from "@reach/skip-nav"; 13 | import "@reach/skip-nav/styles.css"; 14 | 15 | ReactDOM.return( 16 | 17 | {/* put the link at the top of your app */} 18 | 19 |
20 | 21 | {/* and the content next to your main content */} 22 | 23 | 24 |
25 |
, 26 | rootNode 27 | ); 28 | ``` 29 | -------------------------------------------------------------------------------- /packages/skip-nav/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@reach/skip-nav", 3 | "version": "0.18.0", 4 | "description": "Skip navigation links for screen reader and keyboard users.", 5 | "author": "React Training ", 6 | "license": "MIT", 7 | "sideEffects": [ 8 | "*.css" 9 | ], 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/reach/reach-ui.git", 13 | "directory": "packages/skip-nav" 14 | }, 15 | "scripts": { 16 | "build": "tsup" 17 | }, 18 | "dependencies": { 19 | "@reach/polymorphic": "workspace:*" 20 | }, 21 | "devDependencies": { 22 | "@reach-internal/dev": "workspace:*", 23 | "@reach-internal/test": "workspace:*", 24 | "@reach-internal/tsconfig": "workspace:*", 25 | "react": "^17.0.2", 26 | "react-dom": "^17.0.2", 27 | "tsup": "^6.1.3" 28 | }, 29 | "peerDependencies": { 30 | "react": "^16.8.0 || 17.x", 31 | "react-dom": "^16.8.0 || 17.x" 32 | }, 33 | "main": "./src/reach-skip-nav.tsx", 34 | "types": "./src/reach-skip-nav.tsx", 35 | "files": [ 36 | "CHANGELOG.md", 37 | "LICENSE", 38 | "README.md", 39 | "dist", 40 | "styles.css" 41 | ], 42 | "publishConfig": { 43 | "access": "public" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /packages/skip-nav/styles.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --reach-skip-nav: 1; 3 | } 4 | 5 | [data-reach-skip-nav-link] { 6 | border: 0; 7 | clip: rect(0 0 0 0); 8 | height: 1px; 9 | width: 1px; 10 | margin: -1px; 11 | padding: 0; 12 | overflow: hidden; 13 | position: absolute; 14 | } 15 | 16 | [data-reach-skip-nav-link]:focus { 17 | padding: 1rem; 18 | position: fixed; 19 | top: 10px; 20 | left: 10px; 21 | background: white; 22 | z-index: 1; 23 | width: auto; 24 | height: auto; 25 | clip: auto; 26 | } 27 | -------------------------------------------------------------------------------- /packages/skip-nav/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@reach-internal/tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["node_modules", "dist", "__tests__", "examples"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/skip-nav/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import type { defineConfig } from "tsup"; 2 | import { getTsupConfig, getPackageInfo } from "@reach-internal/dev/tsup.js"; 3 | 4 | type TsupConfig = ReturnType; 5 | 6 | let { name: packageName, version: packageVersion } = getPackageInfo( 7 | // @ts-expect-error 8 | __dirname 9 | ); 10 | let cfg: TsupConfig = getTsupConfig(`src/reach-skip-nav.tsx`, { 11 | packageName, 12 | packageVersion, 13 | }); 14 | export default cfg; 15 | -------------------------------------------------------------------------------- /packages/slider/.eslintignore: -------------------------------------------------------------------------------- 1 | dist -------------------------------------------------------------------------------- /packages/slider/README.md: -------------------------------------------------------------------------------- 1 | # @reach/slider 2 | 3 | [![Stable release](https://img.shields.io/npm/v/@reach/slider.svg)](https://npm.im/@reach/slider) ![MIT license](https://badgen.now.sh/badge/license/MIT) 4 | 5 | [Docs](https://reach.tech/slider) | [Source](https://github.com/reach/reach-ui/tree/main/packages/slider) | [WAI-ARIA](https://www.w3.org/TR/wai-aria-practices-1.2/#slider) 6 | 7 | A UI input component where the user selects a value from within a given range. A Slider has a handle that can be moved along a track to change its value. When the user's mouse or focus is on the Slider's handle, the value can be incremented with keyboard controls. 8 | 9 | ```jsx 10 | import { 11 | Slider, 12 | SliderInput, 13 | SliderTrack, 14 | SliderRange, 15 | SliderHandle, 16 | SliderMarker, 17 | } from "@reach/slider"; 18 | import "@reach/slider/styles.css"; 19 | 20 | function Example() { 21 | return ; 22 | } 23 | 24 | function ExampleComposed() { 25 | return ( 26 | 27 | 28 | 29 | 30 | 31 | 32 | ); 33 | } 34 | ``` 35 | -------------------------------------------------------------------------------- /packages/slider/__tests__/slider-axe.test.tsx: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | import * as React from "react"; 5 | import { cleanup, render } from "@reach-internal/test/utils"; 6 | import { axe } from "vitest-axe"; 7 | import { Slider } from "@reach/slider"; 8 | import { afterEach, describe, expect, it, vi } from "vitest"; 9 | 10 | afterEach(cleanup); 11 | 12 | describe(" with axe", () => { 13 | describe("a11y", () => { 14 | it("Should not have ARIA violations", async () => { 15 | vi.useRealTimers(); 16 | const { container } = render(); 17 | const results = await axe(container); 18 | expect(results).toHaveNoViolations(); 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /packages/slider/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@reach/slider", 3 | "version": "0.18.0", 4 | "description": "Accessible React Slider Component", 5 | "author": "React Training ", 6 | "license": "MIT", 7 | "sideEffects": [ 8 | "*.css" 9 | ], 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/reach/reach-ui.git", 13 | "directory": "packages/slider" 14 | }, 15 | "scripts": { 16 | "build": "tsup" 17 | }, 18 | "dependencies": { 19 | "@reach/auto-id": "workspace:*", 20 | "@reach/polymorphic": "workspace:*", 21 | "@reach/utils": "workspace:*" 22 | }, 23 | "devDependencies": { 24 | "@reach-internal/dev": "workspace:*", 25 | "@reach-internal/test": "workspace:*", 26 | "@reach-internal/tsconfig": "workspace:*", 27 | "react": "^17.0.2", 28 | "react-dom": "^17.0.2", 29 | "tsup": "^6.1.3" 30 | }, 31 | "peerDependencies": { 32 | "react": "^16.9.0 || 17.x", 33 | "react-dom": "^16.9.0 || 17.x" 34 | }, 35 | "main": "./src/reach-slider.tsx", 36 | "types": "./src/reach-slider.tsx", 37 | "files": [ 38 | "CHANGELOG.md", 39 | "LICENSE", 40 | "README.md", 41 | "dist", 42 | "styles.css" 43 | ], 44 | "publishConfig": { 45 | "access": "public" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /packages/slider/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@reach-internal/tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["node_modules", "dist", "__tests__", "examples"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/slider/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import type { defineConfig } from "tsup"; 2 | import { getTsupConfig, getPackageInfo } from "@reach-internal/dev/tsup.js"; 3 | 4 | type TsupConfig = ReturnType; 5 | 6 | let { name: packageName, version: packageVersion } = getPackageInfo( 7 | // @ts-expect-error 8 | __dirname 9 | ); 10 | let cfg: TsupConfig = getTsupConfig(`src/reach-slider.tsx`, { 11 | packageName, 12 | packageVersion, 13 | }); 14 | export default cfg; 15 | -------------------------------------------------------------------------------- /packages/tabs/.eslintignore: -------------------------------------------------------------------------------- 1 | dist -------------------------------------------------------------------------------- /packages/tabs/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # `@reach/tabs` 2 | 3 | ## 0.18.0 4 | 5 | ### BREAKING Changes 6 | 7 | - All default exports have been removed. Replace all default imports with the appropriate documented named export. 8 | - The output directory structure has changed slightly. Module files are now named `reach-.mjs` instead of `reach-.esm.js`. 9 | 10 | ### Minor Changes 11 | 12 | - We have simplified our build setup to remove a boatload of dependencies. Build output for all packages may look slightly different, though functionally packages that don't have explicit changes marked in the release notes have not changed. 13 | 14 | This may affect you if you use `patch-package` to modify output code. If you need support for legacy browsers, the new bundle may not transpile the same ECMA features as before. In that case you may want to transpile Reach packages directly. 15 | 16 | - We no longer check that our internal styles are included by looking for a defined CSS custom property. You can still include our base styles as before, but this removes the need to define `--reach-` in your own stylesheets to silence dev warnings. 17 | 18 | ### Patch Changes 19 | 20 | - Updated dependencies: 21 | - `@reach/auto-id@0.18.0` 22 | - `@reach/descendants@0.18.0` 23 | - `@reach/utils@0.18.0` 24 | - `@reach/polymorphic@0.18.0` 25 | -------------------------------------------------------------------------------- /packages/tabs/__tests__/tabs-axe.test.tsx: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | import * as React from "react"; 5 | import { cleanup, act, render } from "@reach-internal/test/utils"; 6 | import { axe } from "vitest-axe"; 7 | import type { AxeCore } from "vitest-axe"; 8 | import { Tabs, TabList, Tab, TabPanels, TabPanel } from "@reach/tabs"; 9 | 10 | import { afterEach, describe, expect, it, vi } from "vitest"; 11 | 12 | afterEach(cleanup); 13 | 14 | describe(" with axe", () => { 15 | it("Should not have ARIA violations", async () => { 16 | vi.useRealTimers(); 17 | const { container } = render( 18 |
19 | 20 | 21 | Tab 1 22 | Tab 2 23 | Tab 3 24 | 25 | 26 | 27 |

Panel 1

28 |
29 | 30 |

Panel 2

31 |
32 | 33 |

Panel 3

34 |
35 |
36 |
37 |
38 | ); 39 | 40 | let results: AxeCore.AxeResults = null as any; 41 | await act(async () => { 42 | results = await axe(container); 43 | }); 44 | expect(results).toHaveNoViolations(); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /packages/tabs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@reach/tabs", 3 | "version": "0.18.0", 4 | "description": "Accessible React Tabs Component", 5 | "author": "React Training ", 6 | "license": "MIT", 7 | "sideEffects": [ 8 | "*.css" 9 | ], 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/reach/reach-ui.git", 13 | "directory": "packages/tabs" 14 | }, 15 | "scripts": { 16 | "build": "tsup" 17 | }, 18 | "dependencies": { 19 | "@reach/auto-id": "workspace:*", 20 | "@reach/descendants": "workspace:*", 21 | "@reach/polymorphic": "workspace:*", 22 | "@reach/utils": "workspace:*" 23 | }, 24 | "devDependencies": { 25 | "@reach-internal/dev": "workspace:*", 26 | "@reach-internal/test": "workspace:*", 27 | "@reach-internal/tsconfig": "workspace:*", 28 | "react": "^17.0.2", 29 | "react-dom": "^17.0.2", 30 | "tsup": "^6.1.3" 31 | }, 32 | "peerDependencies": { 33 | "react": "^16.8.0 || 17.x", 34 | "react-dom": "^16.8.0 || 17.x" 35 | }, 36 | "main": "./src/reach-tabs.tsx", 37 | "types": "./src/reach-tabs.tsx", 38 | "files": [ 39 | "CHANGELOG.md", 40 | "LICENSE", 41 | "README.md", 42 | "dist", 43 | "styles.css" 44 | ], 45 | "publishConfig": { 46 | "access": "public" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /packages/tabs/styles.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --reach-tabs: 1; 3 | } 4 | 5 | [data-reach-tabs][data-orientation="vertical"] { 6 | display: flex; 7 | } 8 | 9 | [data-reach-tab-list] { 10 | display: flex; 11 | background: hsla(0, 0%, 0%, 0.05); 12 | } 13 | 14 | [data-reach-tab-list][aria-orientation="vertical"] { 15 | flex-direction: column; 16 | } 17 | 18 | [data-reach-tab] { 19 | display: inline-block; 20 | border: none; 21 | padding: 0.25em 0.5em; 22 | margin: 0; 23 | border-bottom: 1px solid transparent; 24 | background: none; 25 | color: inherit; 26 | font: inherit; 27 | cursor: pointer; 28 | -webkit-appearance: none; 29 | -moz-appearance: none; 30 | } 31 | 32 | [data-reach-tab]:active { 33 | background: hsla(0, 0%, 0%, 0.05); 34 | } 35 | 36 | [data-reach-tab]:disabled { 37 | opacity: 0.25; 38 | cursor: default; 39 | } 40 | 41 | [data-reach-tab][data-selected] { 42 | border-bottom-color: currentColor; 43 | } 44 | -------------------------------------------------------------------------------- /packages/tabs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@reach-internal/tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["node_modules", "dist", "__tests__", "examples"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/tabs/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import type { defineConfig } from "tsup"; 2 | import { getTsupConfig, getPackageInfo } from "@reach-internal/dev/tsup.js"; 3 | 4 | type TsupConfig = ReturnType; 5 | 6 | let { name: packageName, version: packageVersion } = getPackageInfo( 7 | // @ts-expect-error 8 | __dirname 9 | ); 10 | let cfg: TsupConfig = getTsupConfig(`src/reach-tabs.tsx`, { 11 | packageName, 12 | packageVersion, 13 | }); 14 | export default cfg; 15 | -------------------------------------------------------------------------------- /packages/tooltip/.eslintignore: -------------------------------------------------------------------------------- 1 | dist -------------------------------------------------------------------------------- /packages/tooltip/styles.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --reach-tooltip: 1; 3 | } 4 | 5 | [data-reach-tooltip] { 6 | z-index: 1; 7 | pointer-events: none; 8 | position: absolute; 9 | padding: 0.25em 0.5em; 10 | box-shadow: 2px 2px 10px hsla(0, 0%, 0%, 0.1); 11 | white-space: nowrap; 12 | font-size: 85%; 13 | background: #f0f0f0; 14 | color: #444; 15 | border: solid 1px #ccc; 16 | } 17 | -------------------------------------------------------------------------------- /packages/tooltip/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@reach-internal/tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["node_modules", "dist", "__tests__", "examples"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/tooltip/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import type { defineConfig } from "tsup"; 2 | import { getTsupConfig, getPackageInfo } from "@reach-internal/dev/tsup.js"; 3 | 4 | type TsupConfig = ReturnType; 5 | 6 | let { name: packageName, version: packageVersion } = getPackageInfo( 7 | // @ts-expect-error 8 | __dirname 9 | ); 10 | let cfg: TsupConfig = getTsupConfig(`src/reach-tooltip.tsx`, { 11 | packageName, 12 | packageVersion, 13 | }); 14 | export default cfg; 15 | -------------------------------------------------------------------------------- /packages/utils/.eslintignore: -------------------------------------------------------------------------------- 1 | dist -------------------------------------------------------------------------------- /packages/utils/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # `@reach/utils` 2 | 3 | ## 0.18.0 4 | 5 | ### BREAKING Changes 6 | 7 | - All default exports have been removed. Replace all default imports with the appropriate documented named export. 8 | - The output directory structure has changed slightly. Module files are now named `reach-.mjs` instead of `reach-.esm.js`. 9 | - Removed the `useCheckStyles` export 10 | - All `Polymorphic` types that were previously exported from `@reach/utils` have been moved to a separate package `@reach/polymorphic`. As `@reach/utils` is an internal package, this [breaking] change should not affect you [if you listened to us and did not use the package directly]. 11 | 12 | ### Minor Changes 13 | 14 | - We have simplified our build setup to remove a boatload of dependencies. Build output for all packages may look slightly different, though functionally packages that don't have explicit changes marked in the release notes have not changed. 15 | 16 | This may affect you if you use `patch-package` to modify output code. If you need support for legacy browsers, the new bundle may not transpile the same ECMA features as before. In that case you may want to transpile Reach packages directly. 17 | -------------------------------------------------------------------------------- /packages/utils/README.md: -------------------------------------------------------------------------------- 1 | # @reach/utils 2 | 3 | [![Stable release](https://img.shields.io/npm/v/@reach/utils.svg)](https://npm.im/@reach/utils) ![MIT license](https://badgen.now.sh/badge/license/MIT) 4 | 5 | Shared utilities for various `@reach` packages. 6 | 7 | **Important:** This package is intended for internal use by the Reach UI library. You should not use it directly in your production projects, as the APIs can and will change often without regard to semver. You have been warned! 8 | -------------------------------------------------------------------------------- /packages/utils/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@reach/utils", 3 | "version": "0.18.0", 4 | "description": "Internal, shared utilities for Reach UI.", 5 | "author": "React Training ", 6 | "license": "MIT", 7 | "repository": { 8 | "type": "git", 9 | "url": "git+https://github.com/reach/reach-ui.git", 10 | "directory": "packages/utils" 11 | }, 12 | "scripts": { 13 | "build": "tsup" 14 | }, 15 | "dependencies": {}, 16 | "devDependencies": { 17 | "@reach-internal/dev": "workspace:*", 18 | "@reach-internal/test": "workspace:*", 19 | "@reach-internal/tsconfig": "workspace:*", 20 | "react": "^17.0.2", 21 | "react-dom": "^17.0.2", 22 | "tsup": "^6.1.3" 23 | }, 24 | "peerDependencies": { 25 | "react": "^16.8.0 || 17.x", 26 | "react-dom": "^16.8.0 || 17.x" 27 | }, 28 | "main": "./src/reach-utils.ts", 29 | "types": "./src/reach-utils.ts", 30 | "files": [ 31 | "CHANGELOG.md", 32 | "LICENSE", 33 | "README.md", 34 | "dist" 35 | ], 36 | "publishConfig": { 37 | "access": "public" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/utils/src/can-use-dom.ts: -------------------------------------------------------------------------------- 1 | export function canUseDOM() { 2 | return !!( 3 | typeof window !== "undefined" && 4 | window.document && 5 | window.document.createElement 6 | ); 7 | } 8 | -------------------------------------------------------------------------------- /packages/utils/src/clone-valid-element.ts: -------------------------------------------------------------------------------- 1 | import { cloneElement, isValidElement } from "react"; 2 | import type * as React from "react"; 3 | 4 | /** 5 | * Type-safe clone element 6 | * 7 | * @param element 8 | * @param props 9 | * @param children 10 | */ 11 | export function cloneValidElement( 12 | element: React.ReactElement | React.ReactNode, 13 | props?: Partial & React.Attributes, 14 | ...children: React.ReactNode[] 15 | ): React.ReactElement | React.ReactNode { 16 | return isValidElement(element) 17 | ? cloneElement(element, props, ...children) 18 | : element; 19 | } 20 | -------------------------------------------------------------------------------- /packages/utils/src/compose-event-handlers.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Wraps a lib-defined event handler and a user-defined event handler, returning 3 | * a single handler that allows a user to prevent lib-defined handlers from 4 | * firing. 5 | * 6 | * @param theirHandler User-supplied event handler 7 | * @param ourHandler Library-supplied event handler 8 | */ 9 | export function composeEventHandlers< 10 | EventType extends React.SyntheticEvent | Event 11 | >( 12 | theirHandler: ((event: EventType) => any) | undefined, 13 | ourHandler: (event: EventType) => any 14 | ): (event: EventType) => any { 15 | return (event) => { 16 | theirHandler && theirHandler(event); 17 | if (!event.defaultPrevented) { 18 | return ourHandler(event); 19 | } 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /packages/utils/src/compose-refs.ts: -------------------------------------------------------------------------------- 1 | import { useCallback } from "react"; 2 | import { isFunction } from "./type-check"; 3 | import type { AssignableRef } from "./types"; 4 | 5 | /** 6 | * Passes or assigns an arbitrary value to a ref function or object. 7 | * 8 | * @param ref 9 | * @param value 10 | */ 11 | export function assignRef( 12 | ref: AssignableRef | null | undefined, 13 | value: any 14 | ) { 15 | if (ref == null) return; 16 | if (isFunction(ref)) { 17 | ref(value); 18 | } else { 19 | try { 20 | ref.current = value; 21 | } catch (error) { 22 | throw new Error(`Cannot assign value "${value}" to ref "${ref}"`); 23 | } 24 | } 25 | } 26 | 27 | /** 28 | * Passes or assigns a value to multiple refs (typically a DOM node). Useful for 29 | * dealing with components that need an explicit ref for DOM calculations but 30 | * also forwards refs assigned by an app. 31 | * 32 | * @param refs Refs to fork 33 | */ 34 | export function useComposedRefs( 35 | ...refs: (AssignableRef | null | undefined)[] 36 | ) { 37 | return useCallback((node: any) => { 38 | for (let ref of refs) { 39 | assignRef(ref, node); 40 | } 41 | // eslint-disable-next-line react-hooks/exhaustive-deps 42 | }, refs); 43 | } 44 | -------------------------------------------------------------------------------- /packages/utils/src/computed-styles.ts: -------------------------------------------------------------------------------- 1 | import { getOwnerWindow } from "./owner-document"; 2 | 3 | /** 4 | * Get computed style properties of a DOM element. 5 | * 6 | * @param element 7 | */ 8 | export function getComputedStyles( 9 | element: Element 10 | ): CSSStyleDeclaration | null { 11 | let ownerWindow = getOwnerWindow(element); 12 | if (ownerWindow) { 13 | return ownerWindow.getComputedStyle(element, null); 14 | } 15 | return null; 16 | } 17 | 18 | /** 19 | * Get a computed style value by property. 20 | * 21 | * @param element 22 | * @param styleProp 23 | */ 24 | export function getComputedStyle(element: Element, styleProp: string) { 25 | return getComputedStyles(element)?.getPropertyValue(styleProp) || null; 26 | } 27 | -------------------------------------------------------------------------------- /packages/utils/src/get-document-dimensions.ts: -------------------------------------------------------------------------------- 1 | import { getOwnerDocument } from "./owner-document"; 2 | 3 | /** 4 | * Get the size of the working document minus the scrollbar offset. 5 | * 6 | * @param element 7 | */ 8 | export function getDocumentDimensions( 9 | element?: HTMLElement | null | undefined 10 | ) { 11 | let ownerDocument = getOwnerDocument(element)!; 12 | let ownerWindow = ownerDocument.defaultView || window; 13 | if (!ownerDocument) { 14 | return { 15 | width: 0, 16 | height: 0, 17 | }; 18 | } 19 | 20 | return { 21 | width: ownerDocument.documentElement.clientWidth ?? ownerWindow.innerWidth, 22 | height: 23 | ownerDocument.documentElement.clientHeight ?? ownerWindow.innerHeight, 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /packages/utils/src/get-scroll-position.ts: -------------------------------------------------------------------------------- 1 | import { getOwnerWindow } from "./owner-document"; 2 | 3 | /** 4 | * Get the scoll position of the global window object relative to a given node. 5 | * 6 | * @param element 7 | */ 8 | export function getScrollPosition(element?: HTMLElement | null | undefined) { 9 | let ownerWindow = getOwnerWindow(element); 10 | if (!ownerWindow) { 11 | return { 12 | scrollX: 0, 13 | scrollY: 0, 14 | }; 15 | } 16 | 17 | return { 18 | scrollX: ownerWindow.scrollX, 19 | scrollY: ownerWindow.scrollY, 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /packages/utils/src/get-scrollbar-offset.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Get the scrollbar offset distance. 3 | * 4 | * TODO: Remove in 1.0 (we used this in public examples) 5 | */ 6 | export function getScrollbarOffset() { 7 | try { 8 | if (window.innerWidth > document.documentElement.clientWidth) { 9 | return window.innerWidth - document.documentElement.clientWidth; 10 | } 11 | } catch (err) {} 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /packages/utils/src/is-right-click.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Detects right clicks 3 | * 4 | * @param nativeEvent 5 | */ 6 | export function isRightClick( 7 | nativeEvent: MouseEvent | PointerEvent | TouchEvent 8 | ) { 9 | return "which" in nativeEvent 10 | ? nativeEvent.which === 3 11 | : "button" in nativeEvent 12 | ? (nativeEvent as any).button === 2 13 | : false; 14 | } 15 | -------------------------------------------------------------------------------- /packages/utils/src/make-id.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Joins strings to format IDs for compound components. 3 | * 4 | * @param args 5 | */ 6 | export function makeId(...args: (string | number | null | undefined)[]) { 7 | return args.filter((val) => val != null).join("--"); 8 | } 9 | -------------------------------------------------------------------------------- /packages/utils/src/noop.ts: -------------------------------------------------------------------------------- 1 | export function noop(): void {} 2 | -------------------------------------------------------------------------------- /packages/utils/src/owner-document.ts: -------------------------------------------------------------------------------- 1 | import { canUseDOM } from "./can-use-dom"; 2 | 3 | /** 4 | * Get an element's owner document. Useful when components are used in iframes 5 | * or other environments like dev tools. 6 | * 7 | * @param element 8 | */ 9 | export function getOwnerDocument( 10 | element: T | null | undefined 11 | ) { 12 | return canUseDOM() ? (element ? element.ownerDocument : document) : null; 13 | } 14 | 15 | /** 16 | * TODO: Remove in 1.0 17 | */ 18 | export function getOwnerWindow( 19 | element: T | null | undefined 20 | ) { 21 | let ownerDocument = getOwnerDocument(element); 22 | return ownerDocument ? ownerDocument.defaultView || window : null; 23 | } 24 | -------------------------------------------------------------------------------- /packages/utils/src/reach-utils.ts: -------------------------------------------------------------------------------- 1 | export * from "./can-use-dom"; 2 | export * from "./clone-valid-element"; 3 | export * from "./compose-event-handlers"; 4 | export * from "./compose-refs"; 5 | export * from "./computed-styles"; 6 | export * from "./context"; 7 | export * from "./dev-utils"; 8 | export * from "./get-document-dimensions"; 9 | export * from "./get-scroll-position"; 10 | export * from "./get-scrollbar-offset"; 11 | export * from "./is-right-click"; 12 | export * from "./make-id"; 13 | export * from "./noop"; 14 | export * from "./owner-document"; 15 | export * from "./type-check"; 16 | export * from "./use-constant"; 17 | export * from "./use-controlled-state"; 18 | export * from "./use-event-listener"; 19 | export * from "./use-focus-change"; 20 | export * from "./use-force-update"; 21 | export * from "./use-isomorphic-layout-effect"; 22 | export * from "./use-lazy-ref"; 23 | export * from "./use-previous"; 24 | export * from "./use-stable-callback"; 25 | export * from "./use-stateful-ref-value"; 26 | export * from "./use-update-effect"; 27 | export * from "./types"; 28 | -------------------------------------------------------------------------------- /packages/utils/src/type-check.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Checks whether or not a value is a boolean. 3 | * 4 | * @param value 5 | */ 6 | export function isBoolean(value: any): value is boolean { 7 | return typeof value === "boolean"; 8 | } 9 | 10 | /** 11 | * Checks whether or not a value is a function. 12 | * 13 | * @param value 14 | */ 15 | export function isFunction(value: any): value is Function { 16 | // eslint-disable-next-line eqeqeq 17 | return !!(value && {}.toString.call(value) == "[object Function]"); 18 | } 19 | 20 | /** 21 | * Checks whether or not a value is a number. 22 | * 23 | * @param value 24 | */ 25 | export function isNumber(value: any): value is number { 26 | return typeof value === "number" && !isNaN(value); 27 | } 28 | 29 | /** 30 | * Checks whether or not a value is a string. 31 | * 32 | * @param value 33 | */ 34 | export function isString(value: any): value is string { 35 | return typeof value === "string"; 36 | } 37 | -------------------------------------------------------------------------------- /packages/utils/src/use-constant.ts: -------------------------------------------------------------------------------- 1 | import { useRef } from "react"; 2 | 3 | /** 4 | * React hook for creating a value exactly once. 5 | * @see https://github.com/Andarist/use-constant 6 | */ 7 | export function useConstant(fn: () => ValueType): ValueType { 8 | const ref = useRef<{ v: ValueType }>(); 9 | if (!ref.current) { 10 | ref.current = { v: fn() }; 11 | } 12 | return ref.current.v; 13 | } 14 | -------------------------------------------------------------------------------- /packages/utils/src/use-event-listener.ts: -------------------------------------------------------------------------------- 1 | import { useRef, useEffect } from "react"; 2 | 3 | declare const __DEV__: boolean; 4 | 5 | /** 6 | * Adds a DOM event listener 7 | * 8 | * @param eventName 9 | * @param listener 10 | * @param element 11 | */ 12 | export function useEventListener( 13 | eventName: K, 14 | listener: (event: WindowEventMap[K]) => any, 15 | element: HTMLElement | Document | Window | EventTarget = window 16 | ) { 17 | const savedHandler = useRef(listener); 18 | useEffect(() => { 19 | savedHandler.current = listener; 20 | }, [listener]); 21 | 22 | useEffect(() => { 23 | const isSupported = element && element.addEventListener; 24 | if (!isSupported) { 25 | if (__DEV__) { 26 | console.warn("Event listener not supported on the element provided"); 27 | } 28 | return; 29 | } 30 | 31 | function eventListener(event: WindowEventMap[K]) { 32 | savedHandler.current(event); 33 | } 34 | 35 | element.addEventListener(eventName, eventListener as any); 36 | return () => { 37 | element.removeEventListener(eventName, eventListener as any); 38 | }; 39 | }, [eventName, element]); 40 | } 41 | -------------------------------------------------------------------------------- /packages/utils/src/use-focus-change.ts: -------------------------------------------------------------------------------- 1 | import { useRef, useEffect } from "react"; 2 | 3 | /** 4 | * Detect when focus changes in our document. 5 | * 6 | * @param handleChange 7 | * @param when 8 | * @param ownerDocument 9 | */ 10 | export function useFocusChange( 11 | handleChange: ( 12 | activeElement: Element | null, 13 | previousActiveElement: Element | null, 14 | event?: FocusEvent 15 | ) => void = console.log, 16 | when: "focus" | "blur" = "focus", 17 | ownerDocument: Document = document 18 | ) { 19 | let lastActiveElement = useRef(ownerDocument.activeElement); 20 | 21 | useEffect(() => { 22 | lastActiveElement.current = ownerDocument.activeElement; 23 | 24 | function onChange(event: FocusEvent) { 25 | if (lastActiveElement.current !== ownerDocument.activeElement) { 26 | handleChange( 27 | ownerDocument.activeElement, 28 | lastActiveElement.current, 29 | event 30 | ); 31 | lastActiveElement.current = ownerDocument.activeElement; 32 | } 33 | } 34 | 35 | ownerDocument.addEventListener(when, onChange, true); 36 | 37 | return () => { 38 | ownerDocument.removeEventListener(when, onChange); 39 | }; 40 | }, [when, handleChange, ownerDocument]); 41 | } 42 | -------------------------------------------------------------------------------- /packages/utils/src/use-force-update.ts: -------------------------------------------------------------------------------- 1 | import { useState, useCallback } from "react"; 2 | 3 | /** 4 | * Forces a re-render, similar to `forceUpdate` in class components. 5 | */ 6 | export function useForceUpdate() { 7 | let [, dispatch] = useState<{}>(Object.create(null)); 8 | return useCallback(() => { 9 | dispatch(Object.create(null)); 10 | }, []); 11 | } 12 | -------------------------------------------------------------------------------- /packages/utils/src/use-lazy-ref.ts: -------------------------------------------------------------------------------- 1 | import { useRef } from "react"; 2 | import type * as React from "react"; 3 | 4 | export function useLazyRef any>( 5 | fn: F 6 | ): React.MutableRefObject> { 7 | let isSet = useRef(false); 8 | let ref = useRef(); 9 | if (!isSet.current) { 10 | isSet.current = true; 11 | ref.current = fn(); 12 | } 13 | return ref; 14 | } 15 | -------------------------------------------------------------------------------- /packages/utils/src/use-previous.ts: -------------------------------------------------------------------------------- 1 | import { useRef, useEffect } from "react"; 2 | 3 | /** 4 | * Returns the previous value of a reference after a component update. 5 | * 6 | * @param value 7 | */ 8 | export function usePrevious(value: ValueType) { 9 | const ref = useRef(null); 10 | useEffect(() => { 11 | ref.current = value; 12 | }, [value]); 13 | return ref.current; 14 | } 15 | -------------------------------------------------------------------------------- /packages/utils/src/use-stateful-ref-value.ts: -------------------------------------------------------------------------------- 1 | import { useState, useCallback } from "react"; 2 | 3 | export function useStatefulRefValue( 4 | ref: React.RefObject, 5 | initialState: V 6 | ): [V, (refValue: Exclude) => void] { 7 | let [state, setState] = useState(initialState); 8 | let callbackRef = useCallback((refValue: Exclude) => { 9 | (ref as React.MutableRefObject).current = refValue; 10 | setState(refValue); 11 | // eslint-disable-next-line react-hooks/exhaustive-deps 12 | }, []); 13 | return [state, callbackRef]; 14 | } 15 | -------------------------------------------------------------------------------- /packages/utils/src/use-update-effect.ts: -------------------------------------------------------------------------------- 1 | import { useRef, useEffect } from "react"; 2 | import type * as React from "react"; 3 | 4 | /** 5 | * Call an effect after a component update, skipping the initial mount. 6 | * 7 | * @param effect Effect to call 8 | * @param deps Effect dependency list 9 | */ 10 | export function useUpdateEffect( 11 | effect: React.EffectCallback, 12 | deps?: React.DependencyList 13 | ) { 14 | const mounted = useRef(false); 15 | useEffect(() => { 16 | if (mounted.current) { 17 | effect(); 18 | } else { 19 | mounted.current = true; 20 | } 21 | // eslint-disable-next-line react-hooks/exhaustive-deps 22 | }, deps); 23 | } 24 | -------------------------------------------------------------------------------- /packages/utils/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@reach-internal/tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["node_modules", "dist", "__tests__", "examples"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/utils/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import type { defineConfig } from "tsup"; 2 | import { getTsupConfig, getPackageInfo } from "@reach-internal/dev/tsup.js"; 3 | 4 | type TsupConfig = ReturnType; 5 | 6 | let { name: packageName, version: packageVersion } = getPackageInfo( 7 | // @ts-expect-error 8 | __dirname 9 | ); 10 | let cfg: TsupConfig = getTsupConfig(`src/reach-utils.ts`, { 11 | packageName, 12 | packageVersion, 13 | }); 14 | export default cfg; 15 | -------------------------------------------------------------------------------- /packages/visually-hidden/.eslintignore: -------------------------------------------------------------------------------- 1 | dist -------------------------------------------------------------------------------- /packages/visually-hidden/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # `@reach/visually-hidden` 2 | 3 | ## 0.18.0 4 | 5 | ### BREAKING Changes 6 | 7 | - All default exports have been removed. Replace all default imports with the appropriate documented named export. 8 | - The output directory structure has changed slightly. Module files are now named `reach-.mjs` instead of `reach-.esm.js`. 9 | 10 | ### Minor Changes 11 | 12 | - We have simplified our build setup to remove a boatload of dependencies. Build output for all packages may look slightly different, though functionally packages that don't have explicit changes marked in the release notes have not changed. 13 | 14 | This may affect you if you use `patch-package` to modify output code. If you need support for legacy browsers, the new bundle may not transpile the same ECMA features as before. In that case you may want to transpile Reach packages directly. 15 | 16 | ### Patch Changes 17 | 18 | - Updated dependencies: 19 | - `@reach/polymorphic@0.18.0` 20 | -------------------------------------------------------------------------------- /packages/visually-hidden/README.md: -------------------------------------------------------------------------------- 1 | # @reach/visually-hidden 2 | 3 | [![Stable release](https://img.shields.io/npm/v/@reach/visually-hidden.svg)](https://npm.im/@reach/visually-hidden) ![MIT license](https://badgen.now.sh/badge/license/MIT) 4 | 5 | [Docs](https://reach.tech/visually-hidden) | [Source](https://github.com/reach/reach-ui/tree/main/packages/visually-hidden) | [Origin](https://snook.ca/archives/html_and_css/hiding-content-for-accessibility) | [Further reading](https://a11yproject.com/posts/how-to-hide-content/) 6 | 7 | Provides text for screen readers that is visually hidden. It is the logical opposite of the `aria-hidden` attribute. 8 | 9 | In the following example, screen readers will announce "Save" and will ignore the icon; the browser displays the icon and ignores the text. 10 | 11 | ```jsx 12 | import { VisuallyHidden } from "@reach/visually-hidden"; 13 | 14 | function Example() { 15 | return ( 16 | 20 | ); 21 | } 22 | ``` 23 | -------------------------------------------------------------------------------- /packages/visually-hidden/__tests__/visually-hidden-axe.test.tsx: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | import * as React from "react"; 5 | import { vi, describe, it, expect, afterEach } from "vitest"; 6 | import { render, cleanup } from "@reach-internal/test/utils"; 7 | import { axe } from "vitest-axe"; 8 | import { VisuallyHidden } from "@reach/visually-hidden"; 9 | 10 | afterEach(cleanup); 11 | 12 | describe(" with axe", () => { 13 | it("Should not have ARIA violations", async () => { 14 | vi.useRealTimers(); 15 | const { container } = render( 16 | 20 | ); 21 | const results = await axe(container); 22 | expect(results).toHaveNoViolations(); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /packages/visually-hidden/__tests__/visually-hidden.test.tsx: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | import * as React from "react"; 5 | import { VisuallyHidden } from "@reach/visually-hidden"; 6 | import { describe, it, expect, afterEach } from "vitest"; 7 | import { render, cleanup } from "@reach-internal/test/utils"; 8 | 9 | afterEach(cleanup); 10 | 11 | describe("", () => { 12 | describe("rendering", () => { 13 | it("renders as any HTML element", async () => { 14 | let hiddenMessage = "Hidden Message"; 15 | let { getByText } = render( 16 | {hiddenMessage} 17 | ); 18 | let visuallyHidden = getByText(hiddenMessage); 19 | expect(visuallyHidden.tagName).toBe("DIV"); 20 | }); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /packages/visually-hidden/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@reach/visually-hidden", 3 | "version": "0.18.0", 4 | "description": "Render text that is announced to screen readers but visually hidden.", 5 | "author": "React Training ", 6 | "license": "MIT", 7 | "sideEffects": [ 8 | "*.css" 9 | ], 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/reach/reach-ui.git", 13 | "directory": "packages/visually-hidden" 14 | }, 15 | "scripts": { 16 | "build": "tsup" 17 | }, 18 | "dependencies": { 19 | "@reach/polymorphic": "workspace:*" 20 | }, 21 | "devDependencies": { 22 | "@reach-internal/dev": "workspace:*", 23 | "@reach-internal/test": "workspace:*", 24 | "@reach-internal/tsconfig": "workspace:*", 25 | "react": "^17.0.2", 26 | "react-dom": "^17.0.2", 27 | "tsup": "^6.1.3" 28 | }, 29 | "peerDependencies": { 30 | "react": "^16.8.0 || 17.x || 18.x", 31 | "react-dom": "^16.8.0 || 17.x || 18.x" 32 | }, 33 | "main": "./src/reach-visually-hidden.tsx", 34 | "types": "./src/reach-visually-hidden.tsx", 35 | "files": [ 36 | "CHANGELOG.md", 37 | "LICENSE", 38 | "README.md", 39 | "dist" 40 | ], 41 | "publishConfig": { 42 | "access": "public" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /packages/visually-hidden/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@reach-internal/tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["node_modules", "dist", "__tests__", "examples"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/visually-hidden/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import type { defineConfig } from "tsup"; 2 | import { getTsupConfig, getPackageInfo } from "@reach-internal/dev/tsup.js"; 3 | 4 | type TsupConfig = ReturnType; 5 | 6 | let { name: packageName, version: packageVersion } = getPackageInfo( 7 | // @ts-expect-error 8 | __dirname 9 | ); 10 | let cfg: TsupConfig = getTsupConfig(`src/reach-visually-hidden.tsx`, { 11 | packageName, 12 | packageVersion, 13 | }); 14 | export default cfg; 15 | -------------------------------------------------------------------------------- /packages/window-size/.eslintignore: -------------------------------------------------------------------------------- 1 | dist -------------------------------------------------------------------------------- /packages/window-size/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # `@reach/window-size` 2 | 3 | ## 0.18.0 4 | 5 | ### BREAKING Changes 6 | 7 | - All default exports have been removed. Replace all default imports with the appropriate documented named export. 8 | - The output directory structure has changed slightly. Module files are now named `reach-.mjs` instead of `reach-.esm.js`. 9 | 10 | ### Minor Changes 11 | 12 | - We have simplified our build setup to remove a boatload of dependencies. Build output for all packages may look slightly different, though functionally packages that don't have explicit changes marked in the release notes have not changed. 13 | 14 | This may affect you if you use `patch-package` to modify output code. If you need support for legacy browsers, the new bundle may not transpile the same ECMA features as before. In that case you may want to transpile Reach packages directly. 15 | 16 | - We no longer check that our internal styles are included by looking for a defined CSS custom property. You can still include our base styles as before, but this removes the need to define `--reach-` in your own stylesheets to silence dev warnings. 17 | 18 | ### Patch Changes 19 | 20 | - Updated dependencies: 21 | - `@reach/utils@0.18.0` 22 | -------------------------------------------------------------------------------- /packages/window-size/README.md: -------------------------------------------------------------------------------- 1 | # @reach/window-size 2 | 3 | [![Stable release](https://img.shields.io/npm/v/@reach/window-size.svg)](https://npm.im/@reach/window-size) ![MIT license](https://badgen.now.sh/badge/license/MIT) 4 | 5 | [Docs](https://reach.tech/window-size) | [Source](https://github.com/reach/reach-ui/tree/main/packages/window-size) 6 | 7 | Measure the current window dimensions. 8 | 9 | ```jsx 10 | import WindowSize, { useWindowSize } from "@reach/window-size"; 11 | 12 | function Example() { 13 | const { width, height } = useWindowSize(); 14 | return ( 15 |
16 |

17 | Looks like a pretty{" "} 18 | {width <= 400 ? "small" : width >= 1000 ? "large" : "normal"} screen! 19 |

20 |
21 | ); 22 | } 23 | ``` 24 | -------------------------------------------------------------------------------- /packages/window-size/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@reach/window-size", 3 | "version": "0.18.0", 4 | "description": "Measure the window size in React", 5 | "author": "React Training ", 6 | "license": "MIT", 7 | "sideEffects": [ 8 | "*.css" 9 | ], 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/reach/reach-ui.git", 13 | "directory": "packages/window-size" 14 | }, 15 | "scripts": { 16 | "build": "tsup" 17 | }, 18 | "dependencies": { 19 | "@reach/utils": "workspace:*" 20 | }, 21 | "devDependencies": { 22 | "@reach-internal/dev": "workspace:*", 23 | "@reach-internal/test": "workspace:*", 24 | "@reach-internal/tsconfig": "workspace:*", 25 | "react": "^17.0.2", 26 | "react-dom": "^17.0.2", 27 | "tsup": "^6.1.3" 28 | }, 29 | "peerDependencies": { 30 | "react": "^16.8.0 || 17.x", 31 | "react-dom": "^16.8.0 || 17.x" 32 | }, 33 | "main": "./src/reach-window-size.tsx", 34 | "types": "./src/reach-window-size.tsx", 35 | "files": [ 36 | "CHANGELOG.md", 37 | "LICENSE", 38 | "README.md", 39 | "dist" 40 | ], 41 | "publishConfig": { 42 | "access": "public" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /packages/window-size/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@reach-internal/tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["node_modules", "dist", "__tests__", "examples"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/window-size/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import type { defineConfig } from "tsup"; 2 | import { getTsupConfig, getPackageInfo } from "@reach-internal/dev/tsup.js"; 3 | 4 | type TsupConfig = ReturnType; 5 | 6 | let { name: packageName, version: packageVersion } = getPackageInfo( 7 | // @ts-expect-error 8 | __dirname 9 | ); 10 | let cfg: TsupConfig = getTsupConfig(`src/reach-window-size.tsx`, { 11 | packageName, 12 | packageVersion, 13 | }); 14 | export default cfg; 15 | -------------------------------------------------------------------------------- /playground/.storybook/manager.js: -------------------------------------------------------------------------------- 1 | import { addons } from "@storybook/addons"; 2 | 3 | addons.setConfig({ 4 | enableShortcuts: false, 5 | }); 6 | -------------------------------------------------------------------------------- /playground/.storybook/preview.js: -------------------------------------------------------------------------------- 1 | import "./styles.css"; 2 | -------------------------------------------------------------------------------- /playground/.storybook/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen-Sans, 4 | Ubuntu, Cantarell, Helvetica Neue, sans-serif; 5 | } 6 | 7 | * { 8 | box-sizing: border-box; 9 | } 10 | 11 | #root { 12 | margin: 0.5rem; 13 | } 14 | -------------------------------------------------------------------------------- /playground/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: ["babel-plugin-annotate-pure-calls", "babel-plugin-macros"], 3 | presets: [ 4 | "@babel/preset-typescript", 5 | "@babel/preset-react", 6 | [ 7 | "@babel/preset-env", 8 | { 9 | modules: false, 10 | loose: true, 11 | }, 12 | ], 13 | ], 14 | }; 15 | -------------------------------------------------------------------------------- /playground/stories/accordion.story.ts: -------------------------------------------------------------------------------- 1 | export { Example as Animated } from "./accordion/animated.example"; 2 | export { Example as Basic } from "./accordion/basic.example"; 3 | export { Example as Collapsible } from "./accordion/collapsible.example"; 4 | export { Example as Controlled } from "./accordion/controlled.example"; 5 | export { Example as MultipleCollapsible } from "./accordion/multiple-collapsible.example"; 6 | export { Example as Multiple } from "./accordion/multiple.example"; 7 | export { Example as ReadOnly } from "./accordion/read-only.example"; 8 | export { Example as Styled } from "./accordion/styled.example"; 9 | export { Example as WithArbitraryElements } from "./accordion/with-arbitrary-elements.example"; 10 | export { Example as WithArrows } from "./accordion/with-arrows.example"; 11 | export { Example as WithIndexProp } from "./accordion/with-index-prop.example"; 12 | export { Example as WithUseaccordioncontextHook } from "./accordion/with-useaccordioncontext-hook.example"; 13 | 14 | export default { title: "Accordion" }; 15 | -------------------------------------------------------------------------------- /playground/stories/alert-dialog/basic-ts.example.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { 3 | AlertDialog, 4 | AlertDialogLabel, 5 | AlertDialogDescription, 6 | } from "@reach/alert-dialog"; 7 | 8 | let name = "Basic (TS)"; 9 | 10 | function Example() { 11 | const close = React.useRef(null); 12 | const [showDialog, setShowDialog] = React.useState(false); 13 | return ( 14 |
15 | 16 | {showDialog && ( 17 | 18 | Confirmation! 19 | 20 | Are you sure you want to have that milkshake? 21 | 22 |

23 | {" "} 24 | 27 |

28 |
29 | )} 30 |
31 | ); 32 | } 33 | 34 | Example.storyName = name; 35 | export { Example }; 36 | -------------------------------------------------------------------------------- /playground/stories/alert-dialog/basic.example.js: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { 3 | AlertDialog, 4 | AlertDialogLabel, 5 | AlertDialogDescription, 6 | } from "@reach/alert-dialog"; 7 | 8 | let name = "Example"; 9 | 10 | function Example() { 11 | const close = React.useRef(null); 12 | const [showDialog, setShowDialog] = React.useState(false); 13 | return ( 14 |
15 | 16 | {showDialog && ( 17 | 18 | Confirmation! 19 | 20 | Are you sure you want to have that milkshake? 21 | 22 |

23 | {" "} 24 | 27 |

28 |
29 | )} 30 |
31 | ); 32 | } 33 | 34 | Example.storyName = name; 35 | export { Example }; 36 | -------------------------------------------------------------------------------- /playground/stories/alert-dialog/index.story.js: -------------------------------------------------------------------------------- 1 | export { Example as BasicTsTS } from "./basic-ts.example.tsx"; 2 | export { Example as Basic } from "./basic.example.js"; 3 | 4 | export default { 5 | title: "AlertDialog", 6 | }; 7 | -------------------------------------------------------------------------------- /playground/stories/alert.story.ts: -------------------------------------------------------------------------------- 1 | export { Example as Basic } from "./alert/basic.example"; 2 | 3 | export default { title: "Alert" }; 4 | -------------------------------------------------------------------------------- /playground/stories/checkbox/basic-custom.example.js: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { CustomCheckbox } from "@reach/checkbox"; 3 | import "@reach/checkbox/styles.css"; 4 | import "./basic-custom.css"; 5 | 6 | let name = "Basic CustomCheckbox"; 7 | 8 | function Example() { 9 | return ( 10 |
11 |
e.preventDefault()}> 12 |
13 | 14 | 15 | 19 |
20 |
21 |
22 | 23 |
24 |
25 |
26 | ); 27 | } 28 | 29 | Example.storyName = name; 30 | export { Example }; 31 | -------------------------------------------------------------------------------- /playground/stories/checkbox/basic-mixed.example.js: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { MixedCheckbox } from "@reach/checkbox"; 3 | import "@reach/checkbox/styles.css"; 4 | 5 | let name = "Basic MixedCheckbox"; 6 | 7 | function Example() { 8 | const [checked, setChecked] = React.useState(true); 9 | return ( 10 |
11 |
12 | 16 |
17 |
18 | { 23 | setChecked(event.target.checked); 24 | }} 25 | /> 26 | 29 | 32 | 33 |
34 |
35 | ); 36 | } 37 | 38 | Example.storyName = name; 39 | export { Example }; 40 | -------------------------------------------------------------------------------- /playground/stories/checkbox/hook.example.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { useMixedCheckbox } from "@reach/checkbox"; 3 | import "@reach/checkbox/styles.css"; 4 | 5 | let name = "With useMixedCheckbox hook"; 6 | 7 | function Example() { 8 | const [checked, setChecked] = React.useState(true); 9 | let inputRef = React.useRef(null); 10 | let [inputProps] = useMixedCheckbox(inputRef, { 11 | checked, 12 | onChange: (event) => setChecked(event.target.checked), 13 | }); 14 | return ( 15 |
16 | 20 | 21 |
22 | ); 23 | } 24 | 25 | Example.storyName = name; 26 | export { Example }; 27 | -------------------------------------------------------------------------------- /playground/stories/checkbox/index.story.js: -------------------------------------------------------------------------------- 1 | export { Example as BasicCustom } from "./basic-custom.example.js"; 2 | export { Example as BasicMixed } from "./basic-mixed.example.js"; 3 | export { Example as Checklist } from "./checklist.example.js"; 4 | export { Example as CustomComposed } from "./custom-composed.example.js"; 5 | export { Example as CustomGroup } from "./custom-group.example.js"; 6 | export { Example as Disabled } from "./disabled.example.js"; 7 | export { Example as HookTS } from "./hook.example.tsx"; 8 | 9 | export default { 10 | title: "Checkbox", 11 | }; 12 | -------------------------------------------------------------------------------- /playground/stories/combobox/basic.example.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { 3 | Combobox, 4 | ComboboxInput, 5 | ComboboxList, 6 | ComboboxOption, 7 | ComboboxPopover, 8 | } from "@reach/combobox"; 9 | import { useCityMatch } from "./utils"; 10 | import "@reach/combobox/styles.css"; 11 | 12 | let name = "Basic"; 13 | 14 | function MyCombobox() { 15 | let [term, setTerm] = React.useState(""); 16 | let results = useCityMatch(term); 17 | console.log(results); 18 | 19 | return ( 20 |
21 | 22 | setTerm(event.target.value)} 26 | /> 27 | {results ? ( 28 | 29 | 30 | {results.slice(0, 10).map((result, index) => ( 31 | 35 | ))} 36 | 37 | 38 | ) : null} 39 | 40 |
41 | ); 42 | } 43 | 44 | function Example() { 45 | return ; 46 | } 47 | 48 | Example.storyName = name; 49 | export { Example }; 50 | -------------------------------------------------------------------------------- /playground/stories/combobox/index.story.ts: -------------------------------------------------------------------------------- 1 | export { Example as Basic } from "./basic.example"; 2 | export { Example as ControlledTs } from "./controlled.example"; 3 | export { Example as LotsOfElements } from "./lots-of-elements.example"; 4 | export { Example as NoPopover } from "./no-popover.example"; 5 | export { Example as InForm } from "./in-form.example"; 6 | export { Example as OpenOnFocus } from "./open-on-focus.example"; 7 | // export { Example as SimulatedChange } from "./simulated-change.example.js"; 8 | export { Example as TokenInput } from "./token-input.example"; 9 | export { Example as WithButton } from "./with-button.example"; 10 | export { Example as WithCustomSelectDataTs } from "./with-custom-select-data.example"; 11 | export { Example as WithUsecomboboxcontextHookTS } from "./with-usecomboboxcontext-hook.example"; 12 | 13 | export default { 14 | title: "Combobox", 15 | }; 16 | -------------------------------------------------------------------------------- /playground/stories/combobox/utils.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { matchSorter } from "match-sorter"; 3 | import cities from "./cities"; 4 | import type { City } from "./cities"; 5 | 6 | export function useCityMatch(term: string): City[] | null { 7 | let throttledTerm = useThrottle(term, 100); 8 | return React.useMemo( 9 | () => 10 | term.trim() === "" 11 | ? null 12 | : matchSorter(cities, term, { 13 | keys: [(item) => `${item.city}, ${item.state}`], 14 | }), 15 | // eslint-disable-next-line react-hooks/exhaustive-deps 16 | [throttledTerm] 17 | ); 18 | } 19 | 20 | export function useThrottle(value: any, limit: number) { 21 | const [throttledValue, setThrottledValue] = React.useState(value); 22 | const lastRan = React.useRef(Date.now()); 23 | 24 | React.useEffect(() => { 25 | const handler = window.setTimeout(() => { 26 | if (Date.now() - lastRan.current >= limit) { 27 | setThrottledValue(value); 28 | lastRan.current = Date.now(); 29 | } 30 | }, limit - (Date.now() - lastRan.current)); 31 | 32 | return () => window.clearTimeout(handler); 33 | }, [value, limit]); 34 | 35 | return throttledValue; 36 | } 37 | -------------------------------------------------------------------------------- /playground/stories/dialog.story.ts: -------------------------------------------------------------------------------- 1 | export { Example as Animated } from "./dialog/animated.example"; 2 | export { Example as AriaHidesContent } from "./dialog/aria-hides-content.example"; 3 | export { Example as Autofocus } from "./dialog/autofocus.example"; 4 | export { Example as Basic } from "./dialog/basic.example"; 5 | export { Example as ChangeStyles } from "./dialog/change-styles.example"; 6 | export { Example as CustomFocusLock } from "./dialog/custom-focus-lock.example"; 7 | export { Example as CustomPortalNode } from "./dialog/custom-portal-node.example"; 8 | export { Example as DestroyTrigger } from "./dialog/destroy-trigger.example"; 9 | export { Example as Dismiss } from "./dialog/dismiss.example"; 10 | export { Example as Dropdown } from "./dialog/dropdown.example"; 11 | export { Example as LongContent } from "./dialog/long-content.example"; 12 | export { Example as Nested } from "./dialog/nested.example"; 13 | export { Example as NoTabbables } from "./dialog/no-tabbables.example"; 14 | export { Example as WithDialogOverlay } from "./dialog/with-dialog-overlay.example"; 15 | export { Example as WithTooltip } from "./dialog/with-tooltip.example"; 16 | export { Example as WithWrappedComponents } from "./dialog/with-wrapped-components.example"; 17 | 18 | export default { title: "Dialog" }; 19 | -------------------------------------------------------------------------------- /playground/stories/dialog/autofocus.example.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { Dialog } from "@reach/dialog"; 3 | import "@reach/dialog/styles.css"; 4 | 5 | let name = "Autofocus"; 6 | 7 | function Example() { 8 | const [showDialog, setShowDialog] = React.useState(false); 9 | const button = React.useRef(null); 10 | return ( 11 |
12 | 13 | setShowDialog(false)} 17 | initialFocusRef={button} 18 | > 19 | 20 | 21 | 22 |
23 | ); 24 | } 25 | 26 | Example.storyName = name; 27 | export { Example }; 28 | -------------------------------------------------------------------------------- /playground/stories/dialog/basic.example.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { Dialog } from "@reach/dialog"; 3 | import "@reach/dialog/styles.css"; 4 | 5 | let name = "Basic"; 6 | 7 | function Example() { 8 | const [showDialog, setShowDialog] = React.useState(false); 9 | return ( 10 |
11 | 12 | setShowDialog(false)} 16 | allowPinchZoom 17 | > 18 | 19 |

This is killer!

20 | 21 |
22 | 23 | 24 |
25 |
26 | ); 27 | } 28 | 29 | Example.storyName = name; 30 | export { Example }; 31 | -------------------------------------------------------------------------------- /playground/stories/dialog/dismiss.example.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { Dialog } from "@reach/dialog"; 3 | import "@reach/dialog/styles.css"; 4 | 5 | let name = "Dismiss"; 6 | 7 | function Example() { 8 | const [showDialog, setShowDialog] = React.useState(false); 9 | return ( 10 |
11 | 12 | setShowDialog(false)} 16 | > 17 | 18 |

This is killer!

19 | 20 |
21 | 22 | 23 |
24 |
25 | ); 26 | } 27 | 28 | Example.storyName = name; 29 | export { Example }; 30 | -------------------------------------------------------------------------------- /playground/stories/dialog/dropdown.example.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { action } from "@storybook/addon-actions"; 3 | import { Menu, MenuButton, MenuList, MenuItem } from "@reach/menu-button"; 4 | import { Dialog } from "@reach/dialog"; 5 | import "@reach/menu-button/styles.css"; 6 | import "@reach/dialog/styles.css"; 7 | 8 | let name = "Dropdown"; 9 | 10 | function Example() { 11 | const [showDialog, setShowDialog] = React.useState(false); 12 | return ( 13 |
14 | 15 | setShowDialog(false)} 19 | > 20 | 21 | 22 | Dropdown 23 | 24 | Test 1 25 | Test 2 26 | Test 3 27 | 28 | 29 | 30 |
31 | ); 32 | } 33 | 34 | Example.storyName = name; 35 | export { Example }; 36 | -------------------------------------------------------------------------------- /playground/stories/dialog/long-content.example.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { Dialog } from "@reach/dialog"; 3 | import "@reach/dialog/styles.css"; 4 | 5 | let name = "Long Content"; 6 | 7 | function Example() { 8 | const [showDialog, setShowDialog] = React.useState(false); 9 | return ( 10 |
11 | 12 | {new Array(20).fill(1).map((x, index) => ( 13 |
17 | - scroll - 18 |
19 | ))} 20 | setShowDialog(false)} 24 | > 25 | 26 |

Yikes!

27 |
28 | 29 |
30 |
31 | ); 32 | } 33 | 34 | Example.storyName = name; 35 | export { Example }; 36 | -------------------------------------------------------------------------------- /playground/stories/dialog/nested.example.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { Dialog } from "@reach/dialog"; 3 | import "@reach/dialog/styles.css"; 4 | 5 | let name = "Nested"; 6 | 7 | function Example() { 8 | const [showDialog1, setShowDialog1] = React.useState(false); 9 | const [showDialog2, setShowDialog2] = React.useState(false); 10 | return ( 11 |
12 | 13 | setShowDialog1(false)} 16 | isOpen={showDialog1} 17 | > 18 |
19 | 22 |

You can never have too many design escape hatches

23 | setShowDialog2(false)} 27 | isOpen={showDialog2} 28 | > 29 | 30 | 31 |

Well, maybe you can

32 |
33 |
34 |
35 |
36 | ); 37 | } 38 | 39 | Example.storyName = name; 40 | export { Example }; 41 | -------------------------------------------------------------------------------- /playground/stories/dialog/no-tabbables.example.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { action } from "@storybook/addon-actions"; 3 | import { Dialog } from "@reach/dialog"; 4 | import "@reach/dialog/styles.css"; 5 | 6 | let name = "No Tabbables"; 7 | 8 | function Example() { 9 | const [showDialog, setShowDialog] = React.useState(false); 10 | return ( 11 |
12 | 13 | setShowDialog(false)} 17 | onFocus={action("Focused!")} 18 | > 19 |

There are no tabbables here

20 |

Tab should focus the element itself

21 |
22 |
23 | ); 24 | } 25 | 26 | Example.storyName = name; 27 | export { Example }; 28 | -------------------------------------------------------------------------------- /playground/stories/dialog/with-dialog-overlay.example.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { DialogOverlay, DialogContent } from "@reach/dialog"; 3 | import "@reach/dialog/styles.css"; 4 | 5 | let name = "With Separate Overlay"; 6 | 7 | function Example() { 8 | const overlayRef = React.useRef(null); 9 | const contentRef = React.useRef(null); 10 | const [showDialog, setShowDialog] = React.useState(false); 11 | const open = () => setShowDialog(true); 12 | const close = () => setShowDialog(false); 13 | 14 | return ( 15 |
16 | 17 | 18 | 24 | 29 |

30 | The overlay styles are a white fade instead of the default black 31 | fade. 32 |

33 | 34 |
35 |
36 |
37 | ); 38 | } 39 | 40 | Example.storyName = name; 41 | export { Example }; 42 | -------------------------------------------------------------------------------- /playground/stories/dialog/with-tooltip.example.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { Dialog } from "@reach/dialog"; 3 | import { Tooltip } from "@reach/tooltip"; 4 | import "@reach/dialog/styles.css"; 5 | import "@reach/tooltip/styles.css"; 6 | 7 | let name = "With Tooltip"; 8 | 9 | function Example() { 10 | const [showDialog, setShowDialog] = React.useState(false); 11 | return ( 12 |
13 | 14 | 19 | 20 | setShowDialog(false)} 24 | allowPinchZoom 25 | > 26 | 27 |

This is killer!

28 | 29 |
30 | 31 | 32 |
33 |
34 | ); 35 | } 36 | 37 | Example.storyName = name; 38 | export { Example }; 39 | -------------------------------------------------------------------------------- /playground/stories/disclosure.story.ts: -------------------------------------------------------------------------------- 1 | export { Example as Basic } from "./disclosure/basic.example"; 2 | export { Example as Controlled } from "./disclosure/controlled.example"; 3 | 4 | export default { title: "Disclosure" }; 5 | -------------------------------------------------------------------------------- /playground/stories/disclosure/basic.example.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { 3 | Disclosure, 4 | DisclosureButton, 5 | DisclosurePanel, 6 | } from "@reach/disclosure"; 7 | 8 | let name = "Basic"; 9 | 10 | function Example() { 11 | return ( 12 | 13 | I have a secret 14 | 15 | Ante rhoncus facilisis iaculis nostra faucibus vehicula ac consectetur 16 | pretium, lacus nunc consequat id viverra facilisi ligula eleifend, 17 | congue gravida malesuada proin scelerisque luctus est convallis. 18 | 19 | 20 | ); 21 | } 22 | 23 | Example.storyName = name; 24 | export { Example }; 25 | -------------------------------------------------------------------------------- /playground/stories/listbox.story.ts: -------------------------------------------------------------------------------- 1 | export { Example as Basic } from "./listbox/basic.example"; 2 | export { Example as Composed } from "./listbox/composed.example"; 3 | export { Example as Controlled } from "./listbox/controlled.example"; 4 | export { Example as Dynamic } from "./listbox/dynamic-content.example"; 5 | export { Example as FocusOnSelect } from "./listbox/focus-on-select.example"; 6 | export { Example as GroupedComposedLabel } from "./listbox/grouped-composed-label.example"; 7 | export { Example as GroupedTS } from "./listbox/grouped.example"; 8 | export { Example as PositionOverActive } from "./listbox/position-over-active.example"; 9 | export { Example as Styled } from "./listbox/styled.example"; 10 | export { Example as WithForm } from "./listbox/in-form.example"; 11 | export { Example as WithNestedTabbables } from "./listbox/with-nested-tabbables.example"; 12 | export { Example as WithUselistboxcontextHook } from "./listbox/with-uselistboxcontext-hook.example"; 13 | 14 | export default { title: "Listbox" }; 15 | -------------------------------------------------------------------------------- /playground/stories/listbox/common.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | export const Tag: React.FC> = ( 4 | props 5 | ) => { 6 | let [innerText, setInnerText] = React.useState(null); 7 | let ref = React.useRef(null); 8 | let setInnerTextRef = React.useCallback((node: HTMLSpanElement) => { 9 | ref.current = node; 10 | if (node) { 11 | setInnerText(node.innerText); 12 | } 13 | }, []); 14 | return ( 15 | 32 | ); 33 | }; 34 | 35 | export function Taco() { 36 | return ( 37 | 38 | 🌮 39 | 40 | ); 41 | } 42 | -------------------------------------------------------------------------------- /playground/stories/menu-button/animate.css: -------------------------------------------------------------------------------- 1 | @keyframes slide-down { 2 | 0% { 3 | opacity: 0; 4 | transform: translateY(-10px); 5 | } 6 | 100% { 7 | opacity: 1; 8 | transform: translateY(0); 9 | } 10 | } 11 | 12 | .slide-down[data-reach-menu-list], 13 | .slide-down[data-reach-menu-items] { 14 | border-radius: 5px; 15 | animation: slide-down 0.2s ease; 16 | } 17 | -------------------------------------------------------------------------------- /playground/stories/menu-button/animated.example.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { Menu, MenuList, MenuButton, MenuItem } from "@reach/menu-button"; 3 | import { action } from "@storybook/addon-actions"; 4 | import "@reach/menu-button/styles.css"; 5 | import "./animate.css"; 6 | 7 | let name = "Animated"; 8 | 9 | function Example() { 10 | return ( 11 | 12 | 13 | Actions 14 | 15 | 16 | Download 17 | Create a Copy 18 | Mark as Draft 19 | Delete 20 | 21 | 22 | ); 23 | } 24 | 25 | Example.storyName = name; 26 | export { Example }; 27 | -------------------------------------------------------------------------------- /playground/stories/menu-button/custom-wrapper.example.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { action } from "@storybook/addon-actions"; 3 | import { 4 | Menu, 5 | MenuPopover, 6 | MenuItems, 7 | MenuButton, 8 | MenuItem, 9 | } from "@reach/menu-button"; 10 | import "@reach/menu-button/styles.css"; 11 | 12 | let name = "With Custom Wrapper"; 13 | 14 | function Example() { 15 | return ( 16 | 17 | 18 | Actions 19 | 20 | 21 |
22 | 23 | Download 24 | Create a Copy 25 | 26 | Mark as Draft 27 | 28 | Delete 29 | 30 |
31 |
32 |
33 | ); 34 | } 35 | 36 | Example.storyName = name; 37 | export { Example }; 38 | -------------------------------------------------------------------------------- /playground/stories/menu-button/no-portal.example.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { Menu, MenuList, MenuButton, MenuItem } from "@reach/menu-button"; 3 | import { action } from "@storybook/addon-actions"; 4 | import "@reach/menu-button/styles.css"; 5 | 6 | let name = "Inline list (no portal)"; 7 | 8 | function Example() { 9 | return ( 10 | 11 | 12 | Actions 13 | 14 | 15 | Download 16 | Create a Copy 17 | Mark as Draft 18 | Delete 19 | 20 | 21 | ); 22 | } 23 | 24 | Example.storyName = name; 25 | export { Example }; 26 | -------------------------------------------------------------------------------- /playground/stories/menu-button/pete-older.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reach/reach-ui/b3d94d22811db6b5c0f272b9a7e2e3c1bb4699ae/playground/stories/menu-button/pete-older.png -------------------------------------------------------------------------------- /playground/stories/menu-button/pete-younger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reach/reach-ui/b3d94d22811db6b5c0f272b9a7e2e3c1bb4699ae/playground/stories/menu-button/pete-younger.png -------------------------------------------------------------------------------- /playground/stories/menu-button/render-prop.example.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { action } from "@storybook/addon-actions"; 3 | import { Menu, MenuList, MenuButton, MenuItem } from "@reach/menu-button"; 4 | import "@reach/menu-button/styles.css"; 5 | 6 | let name = "Render Prop"; 7 | 8 | function Example() { 9 | return ( 10 | 11 | {({ isExpanded }) => ( 12 | 13 | 14 | {isExpanded ? "Close" : "Open"} 15 | 16 | 17 | Download 18 | Create a Copy 19 | 20 | Mark as Draft 21 | 22 | Delete 23 | 24 | 25 | )} 26 | 27 | ); 28 | } 29 | 30 | Example.storyName = name; 31 | export { Example }; 32 | -------------------------------------------------------------------------------- /playground/stories/menu-button/with-disabled-items.example.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { Menu, MenuList, MenuButton, MenuItem } from "@reach/menu-button"; 3 | import { action } from "@storybook/addon-actions"; 4 | import "@reach/menu-button/styles.css"; 5 | 6 | let name = "With Disabled Items"; 7 | 8 | function Example() { 9 | let [disabled, setDisabled] = React.useState(true); 10 | return ( 11 |
12 | 13 | 14 | Actions 15 | 16 | 17 | 18 | Download 19 | 20 | Copy 21 | Create 22 | 23 | Mark as Draft 24 | 25 | Delete 26 | 27 | 28 | 31 |
32 | ); 33 | } 34 | 35 | Example.storyName = name; 36 | export { Example }; 37 | -------------------------------------------------------------------------------- /playground/stories/menu-button/with-other-tabbables.example.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { action } from "@storybook/addon-actions"; 3 | import { Menu, MenuList, MenuButton, MenuItem } from "@reach/menu-button"; 4 | import "@reach/menu-button/styles.css"; 5 | 6 | let name = "With Other Tabbables"; 7 | 8 | function Example() { 9 | return ( 10 |
11 |

12 | 13 | 18 |

19 | 20 | 21 | Actions 22 | 23 | 24 | Download 25 | Create a Copy 26 | Mark as Draft 27 | Delete 28 | 29 | 30 | 31 |
32 | ); 33 | } 34 | 35 | Example.storyName = name; 36 | export { Example }; 37 | -------------------------------------------------------------------------------- /playground/stories/menu-button/with-render-props.example.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { Menu, MenuList, MenuButton, MenuItem } from "@reach/menu-button"; 3 | import { action } from "@storybook/addon-actions"; 4 | import "@reach/menu-button/styles.css"; 5 | 6 | let name = "With Render Props"; 7 | 8 | function Example() { 9 | return ( 10 | 11 | {() => ( 12 | 13 | 14 | Actions 15 | 16 | 17 | Download 18 | Create a Copy 19 | 20 | Mark as Draft 21 | 22 | Delete 23 | 24 | 25 | )} 26 | 27 | ); 28 | } 29 | 30 | Example.storyName = name; 31 | export { Example }; 32 | -------------------------------------------------------------------------------- /playground/stories/menu-button/with-tooltip.example.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable jsx-a11y/accessible-emoji */ 2 | 3 | import * as React from "react"; 4 | import { action } from "@storybook/addon-actions"; 5 | import { Menu, MenuList, MenuButton, MenuItem } from "@reach/menu-button"; 6 | import { Tooltip } from "@reach/tooltip"; 7 | import "@reach/menu-button/styles.css"; 8 | import "@reach/tooltip/styles.css"; 9 | 10 | let name = "With Tooltip"; 11 | 12 | function Example() { 13 | return ( 14 | 15 | 16 | 17 | 🍔 18 | 19 | 20 | 21 | Download 22 | Create a Copy 23 | Mark as Draft 24 | Delete 25 | 26 | 27 | ); 28 | } 29 | 30 | Example.storyName = name; 31 | export { Example }; 32 | -------------------------------------------------------------------------------- /playground/stories/popover.story.ts: -------------------------------------------------------------------------------- 1 | export { Example as Basic } from "./popover/basic.example"; 2 | export { Example as Hidden } from "./popover/hidden.example"; 3 | 4 | export default { title: "Popover" }; 5 | -------------------------------------------------------------------------------- /playground/stories/portal.story.ts: -------------------------------------------------------------------------------- 1 | export { Example as Basic } from "./portal/basic.example"; 2 | 3 | export default { title: "Portal" }; 4 | -------------------------------------------------------------------------------- /playground/stories/portal/basic.example.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { Portal } from "@reach/portal"; 3 | 4 | let name = "Basic"; 5 | 6 | function Example() { 7 | return ( 8 |
14 |
15 | This is in the normal react root, with an overflow hidden parent, clips 16 | the box. 17 |
18 | 19 |
30 | This is in the portal, rendered in the DOM at the document root so the 31 | CSS doesn't screw things up, but we render it in the react hierarchy 32 | where it makes sense. 33 |
34 |
35 |
36 | ); 37 | } 38 | 39 | Example.storyName = name; 40 | export { Example }; 41 | -------------------------------------------------------------------------------- /playground/stories/rect.story.js: -------------------------------------------------------------------------------- 1 | export { Example as Basic } from "./rect/basic.example"; 2 | export { Example as BasicUseRect } from "./rect/basic-use-rect.example"; 3 | export { Example as ChangeObservedRef } from "./rect/change-observed-ref.example"; 4 | export { Example as Pin } from "./rect/pin.example"; 5 | export { Example as PinUseRect } from "./rect/pin-use-rect.example"; 6 | 7 | export default { title: "Rect" }; 8 | -------------------------------------------------------------------------------- /playground/stories/rect/basic-use-rect.example.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { useRect } from "@reach/rect"; 3 | 4 | let name = "Basic (useRect)"; 5 | 6 | function Example() { 7 | let ref = React.useRef(null); 8 | let rect = useRect(ref, { observe: true }); 9 | return ( 10 |
11 |
{JSON.stringify(rect, null, 2)}
12 |