diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index ddc20f2d84..1e050c9ba7 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -2,6 +2,14 @@ Thanks for your interest in contributing to Headless UI! Please take a moment to review this document **before submitting a pull request**. +- [Pull requests](#pull-requests) +- [Monorepo](#monorepo) +- [Installation](#installation) +- [Coding standards](#coding-standards) +- [Running tests](#running-tests) +- [Running playgrounds](#running-playgrounds) +- [Scripts summary](#scripts-summary) + ## Pull requests **Please ask first before starting work on any significant new features.** @@ -11,22 +19,28 @@ Also make sure that you are making changes to both the `React` and `Vue` version ## Monorepo -The Headless UI repo is a monorepo using `yarn` workspaces. Note that we are using `yarn` version 1. +The Headless UI repo is a monorepo using `yarn` workspaces. Note that we are using `yarn` **version 1**. -## Coding standards +## Installation -Our code formatting rules are defined by TSDX, which uses `eslint` and we also use `prettier`. You can check your code against these standards by running: +You only require a `yarn install` in the root directory to install everything you need. ```sh -yarn lint +yarn install ``` +## Coding standards + +We use `prettier` for making sure that the codebase is formatted consistently. To automatically fix any style violations in your code, you can run: ```sh -yarn lint --fix +yarn lint ``` +**Note**: Whenever you commit, the lint check will run on all staged files. +**Note**: In CI, we will only check your code, and not write with the formatted files. If you want to just check, then you can either run `yarn lint-check` or `CI=true yarn lint` + ## Running tests You can run the test suite using the following commands: @@ -47,3 +61,61 @@ yarn vue test Please ensure that the tests are passing when submitting a pull request. If you're adding new features to Headless UI, please include tests. +## Running playgrounds + +Currently the `React` playground (located in `packages/playground-react`) is a Next.js app that contains some examples which you can find in the `pages` directory. The `Vue` playground (located in `packages/playground-vue`) is a Vite app that contains some examples which you can find in the `src/components` directory. + +You can launch them by running: + +```sh +yarn react playground + +# or + +yarn vue playground +``` + +This will also start the necessary watchers so that you don't have to care about them. + +## Scripts summary + +Global scripts, and some aliases: + +- `yarn install`: install all dependencies for all packages +- `yarn clean`: this will call all `yarn {package} clean` commands +- `yarn build`: this will call all `yarn {package} build` commands +- `yarn lint`: this will `lint` all packages +- `yarn test`: this will `test` all packages + - `yarn test`: run all jest tests + - `yarn test --watch`: run all jest tests in interactive mode + - `yarn test tabs`: run all jest tests filtered by `tabs` + - `yarn test tabs --watch`: run all jest tests in interactive mode filtered by `tabs` + +Scripts per package: + +- `yarn react`: Prefix to run anything in the `@headlessui/react` package + - `yarn react test`: run all jest tests + - `yarn react test --watch`: run all jest tests in interactive mode + - `yarn react test tabs`: run all jest tests filtered by `tabs` + - `yarn react test tabs --watch`: run all jest tests in interactive mode filtered by `tabs` + - `yarn react build`: build the final artefacts + - `yarn react lint`: validate and fix the react codebase using prettier + - `yarn react watch`: start a watcher for the react esm build + - **Note**: this will be executed for you when using the `yarn react playground` + - **Note**: this is not required for jest. You will probably never need this + - `yarn react playground`: (alias) start a development server in the `playground-react` package + - **Note**: this will also run `yarn react watch` for you, which means that you only need to execute `yarn react playground` + - `yarn react clean`: this will remove `dist` files +- `yarn vue`: Prefix to run anything in the `@headlessui/vue` package + - `yarn vue test`: run all jest tests + - `yarn vue test --watch`: run all jest tests in interactive mode + - `yarn vue test tabs`: run all jest tests filtered by `tabs` + - `yarn vue test tabs --watch`: run all jest tests in interactive mode filtered by `tabs` + - `yarn vue build`: build the final artefacts + - `yarn vue lint`: validate and fix the vue codebase using prettier + - `yarn vue watch`: start a watcher for the vue esm build + - **Note**: this will be executed for you when using the `yarn vue playground` + - **Note**: this is not required for jest. You will probably never need this + - `yarn vue playground`: (alias) start a development server in the `playground-vue` package + - **Note**: this will also run `yarn vue watch` for you, which means that you only need to execute `yarn react playground` + - `yarn vue clean`: this will remove `dist` files diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index fbdfa1eeb7..347a88b719 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -12,4 +12,3 @@ contact_links: - name: Documentation Issue url: https://github.com/tailwindlabs/headlessui/issues/new?title=%5BDOCS%5D:%20 about: 'For documentation issues, suggest changes on our documentation repository.' - diff --git a/.github/workflows/release-insiders.yml b/.github/workflows/release-insiders.yml index b7bbc85525..e6891facb4 100644 --- a/.github/workflows/release-insiders.yml +++ b/.github/workflows/release-insiders.yml @@ -44,7 +44,7 @@ jobs: id: vars run: echo "::set-output name=sha_short::$(git rev-parse --short HEAD)" - - name: "Version based on commit: 0.0.0-insiders.${{ steps.vars.outputs.sha_short }}" + - name: 'Version based on commit: 0.0.0-insiders.${{ steps.vars.outputs.sha_short }}' run: npm version -w packages 0.0.0-insiders.${{ steps.vars.outputs.sha_short }} --force --no-git-tag-version - name: Publish @@ -52,4 +52,3 @@ jobs: env: CI: true NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000000..62815c2732 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,4 @@ +dist/ +node_modules/ +coverage/ +.next/ diff --git a/.swcrc b/.swcrc new file mode 100644 index 0000000000..0c4dc7af87 --- /dev/null +++ b/.swcrc @@ -0,0 +1,11 @@ +{ + "minify": false, + "jsc": { + "parser": { + "syntax": "typescript", + "tsx": true, + "decorators": false, + "dynamicImport": false + } + } +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 44cccf4e3d..e02468b748 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Ensure correct order when conditionally rendering `Menu.Item`, `Listbox.Option` and `RadioGroup.Option` ([#1045](https://github.com/tailwindlabs/headlessui/pull/1045)) - Improve controlled Tabs behaviour ([#1050](https://github.com/tailwindlabs/headlessui/pull/1050)) - Improve typeahead search logic ([#1051](https://github.com/tailwindlabs/headlessui/pull/1051)) +- Improve overal codebase, use modern tech like `esbuild` and TypeScript 4! ([#1055](https://github.com/tailwindlabs/headlessui/pull/1055)) + +### Added + +- Add `Combobox` component ([#1047](https://github.com/tailwindlabs/headlessui/pull/1047)) ## [Unreleased - @headlessui/vue] @@ -19,6 +24,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Ensure correct order when conditionally rendering `MenuItem`, `ListboxOption` and `RadioGroupOption` ([#1045](https://github.com/tailwindlabs/headlessui/pull/1045)) - Improve typeahead search logic ([#1051](https://github.com/tailwindlabs/headlessui/pull/1051)) +- Improve overal codebase, use modern tech like `esbuild` and TypeScript 4! ([#1055](https://github.com/tailwindlabs/headlessui/pull/1055)) + +### Added + +- Add `Combobox` component ([#1047](https://github.com/tailwindlabs/headlessui/pull/1047)) ## [@headlessui/react@v1.4.3] - 2022-01-14 @@ -88,7 +98,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add `aria-orientation` to `Listbox`, which swaps Up/Down with Left/Right keys ([#683](https://github.com/tailwindlabs/headlessui/pull/683)) - Expose `close` function from the render prop for `Disclosure`, `Disclosure.Panel`, `Popover` and `Popover.Panel` ([#697](https://github.com/tailwindlabs/headlessui/pull/697)) - ## [@headlessui/vue@v1.4.0] - 2021-07-29 ### Added @@ -100,7 +109,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [@headlessui/react@v1.3.0] - 2021-06-21 -### Added +### Added - Ensure that you can use `Transition.Child` when using implicit Transitions ([#503](https://github.com/tailwindlabs/headlessui/pull/503)) - Add new `entered` prop for `Transition` and `Transition.Child` components ([#504](https://github.com/tailwindlabs/headlessui/pull/504)) @@ -120,7 +129,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [@headlessui/vue@v1.3.0] - 2021-06-21 -### Added +### Added - Ensure that you can use `TransitionChild` when using implicit Transitions ([#503](https://github.com/tailwindlabs/headlessui/pull/503)) - Add new `entered` prop for `Transition` and `TransitionChild` components ([#504](https://github.com/tailwindlabs/headlessui/pull/504)) @@ -134,7 +143,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [@headlessui/react@v1.2.0] - 2021-05-10 -### Added +### Added - Introduce Open/Closed state, to simplify component communication ([#466](https://github.com/tailwindlabs/headlessui/pull/466)) @@ -146,7 +155,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [@headlessui/vue@v1.2.0] - 2021-05-10 -### Added +### Added - Introduce Open/Closed state, to simplify component communication ([#466](https://github.com/tailwindlabs/headlessui/pull/466)) diff --git a/README.md b/README.md index 30a518bf84..5f42a558a9 100644 --- a/README.md +++ b/README.md @@ -49,4 +49,3 @@ For casual chit-chat with others using the library: ## Contributing If you're interested in contributing to Headless UI, please read our [contributing docs](https://github.com/tailwindlabs/headlessui/blob/main/.github/CONTRIBUTING.md) **before submitting a pull request**. - diff --git a/jest/create-jest-config.js b/jest/create-jest-config.js index 5cbedca808..bbeb0b88a0 100644 --- a/jest/create-jest-config.js +++ b/jest/create-jest-config.js @@ -1,17 +1,10 @@ -const { createJestConfig: create } = require('tsdx/dist/createJestConfig') - module.exports = function createJestConfig(root, options) { return Object.assign( - {}, - create(undefined, root), { rootDir: root, setupFilesAfterEnv: ['../../jest/custom-matchers.ts'], - globals: { - 'ts-jest': { - isolatedModules: true, - tsConfig: '/tsconfig.tsdx.json', - }, + transform: { + '^.+\\.(t|j)sx?$': '@swc/jest', }, }, options diff --git a/package.json b/package.json index b4996f4678..89c1170fce 100644 --- a/package.json +++ b/package.json @@ -11,11 +11,16 @@ ], "scripts": { "react": "yarn workspace @headlessui/react", + "react-playground": "yarn workspace playground-react dev", + "playground-react": "yarn workspace playground-react dev", "vue": "yarn workspace @headlessui/vue", - "shared": "yarn workspace @headlessui/shared", - "build": "yarn workspaces run build", + "playground-vue": "yarn workspace playground-vue dev", + "vue-playground": "yarn workspace playground-vue dev", + "clean": "yarn workspaces run clean", + "build": "npm-run-all -p 'react build' 'vue build'", "test": "./scripts/test.sh", - "lint": "./scripts/lint.sh" + "lint": "./scripts/lint.sh", + "lint-check": "CI=true ./scripts/lint.sh" }, "husky": { "hooks": { @@ -23,7 +28,7 @@ } }, "lint-staged": { - "*.{js,jsx,ts,tsx}": "tsdx lint" + "*": "yarn lint-check" }, "prettier": { "printWidth": 100, @@ -32,12 +37,19 @@ "trailingComma": "es5" }, "devDependencies": { + "@swc/core": "^1.2.131", + "@swc/jest": "^0.2.17", "@testing-library/jest-dom": "^5.11.9", "@types/node": "^14.14.22", + "esbuild": "^0.14.11", "husky": "^4.3.8", + "jest": "26", "lint-staged": "^12.2.1", - "tsdx": "^0.14.1", - "tslib": "^2.1.0", - "typescript": "^3.9.7" + "npm-run-all": "^4.1.5", + "prettier": "^2.5.1", + "prettier-plugin-tailwindcss": "^0.1.4", + "rimraf": "^3.0.2", + "tslib": "^2.3.1", + "typescript": "^4.5.4" } } diff --git a/packages/@headlessui-react/README.md b/packages/@headlessui-react/README.md index fa2a630f49..733df5c86a 100644 --- a/packages/@headlessui-react/README.md +++ b/packages/@headlessui-react/README.md @@ -36,4 +36,3 @@ For help, discussion about best practices, or any other conversation that would For casual chit-chat with others using the library: [Join the Tailwind CSS Discord Server](https://discord.gg/7NF8GNe) - diff --git a/packages/@headlessui-react/build/index.js b/packages/@headlessui-react/build/index.js new file mode 100644 index 0000000000..473f46702e --- /dev/null +++ b/packages/@headlessui-react/build/index.js @@ -0,0 +1,7 @@ +'use strict' + +if (process.env.NODE_ENV === 'production') { + module.exports = require('./headlessui.prod.cjs.js') +} else { + module.exports = require('./headlessui.dev.cjs.js') +} diff --git a/packages/@headlessui-react/package.json b/packages/@headlessui-react/package.json index f9b2721cdc..63d805cfe5 100644 --- a/packages/@headlessui-react/package.json +++ b/packages/@headlessui-react/package.json @@ -4,12 +4,21 @@ "description": "A set of completely unstyled, fully accessible UI components for React, designed to integrate beautifully with Tailwind CSS.", "main": "dist/index.js", "typings": "dist/index.d.ts", - "module": "dist/index.esm.js", + "module": "dist/headlessui.esm.js", "license": "MIT", "files": [ "README.md", "dist" ], + "exports": { + ".": { + "import": { + "default": "./dist/headlessui.esm.js" + }, + "require": "./dist/index.js", + "types": "./dist/index.d.ts" + } + }, "sideEffects": false, "engines": { "node": ">=10" @@ -24,9 +33,12 @@ }, "scripts": { "prepublishOnly": "npm run build", + "build": "../../scripts/build.sh --external:react --external:react-dom", + "watch": "../../scripts/watch.sh --external:react --external:react-dom", "test": "../../scripts/test.sh", - "build": "../../scripts/build.sh", - "lint": "../../scripts/lint.sh" + "lint": "../../scripts/lint.sh", + "playground": "yarn workspace playground-react dev", + "clean": "rimraf ./dist" }, "peerDependencies": { "react": "^16 || ^17 || ^18", @@ -38,6 +50,7 @@ "@types/react-dom": "^16.9.10", "react": "^16.14.0", "react-dom": "^16.14.0", - "snapshot-diff": "^0.8.1" + "snapshot-diff": "^0.8.1", + "esbuild": "^0.11.18" } } diff --git a/packages/@headlessui-react/src/components/combobox/combobox.test.tsx b/packages/@headlessui-react/src/components/combobox/combobox.test.tsx new file mode 100644 index 0000000000..e5f79c50fc --- /dev/null +++ b/packages/@headlessui-react/src/components/combobox/combobox.test.tsx @@ -0,0 +1,4919 @@ +import React, { createElement, useState, useEffect } from 'react' +import { render } from '@testing-library/react' + +import { Combobox } from './combobox' +import { suppressConsoleLogs } from '../../test-utils/suppress-console-logs' +import { + click, + focus, + mouseMove, + mouseLeave, + press, + shift, + type, + word, + Keys, + MouseButton, +} from '../../test-utils/interactions' +import { + assertActiveElement, + assertActiveComboboxOption, + assertComboboxList, + assertComboboxButton, + assertComboboxButtonLinkedWithCombobox, + assertComboboxButtonLinkedWithComboboxLabel, + assertComboboxOption, + assertComboboxLabel, + assertComboboxLabelLinkedWithCombobox, + assertNoActiveComboboxOption, + assertNoSelectedComboboxOption, + getComboboxInput, + getComboboxButton, + getComboboxButtons, + getComboboxInputs, + getComboboxOptions, + getComboboxLabel, + ComboboxState, + getByText, + getComboboxes, +} from '../../test-utils/accessibility-assertions' +import { Transition } from '../transitions/transition' + +let NOOP = () => {} + +jest.mock('../../hooks/use-id') + +beforeAll(() => { + jest.spyOn(window, 'requestAnimationFrame').mockImplementation(setImmediate as any) + jest.spyOn(window, 'cancelAnimationFrame').mockImplementation(clearImmediate as any) +}) + +afterAll(() => jest.restoreAllMocks()) + +describe('safeguards', () => { + it.each([ + ['Combobox.Button', Combobox.Button], + ['Combobox.Label', Combobox.Label], + ['Combobox.Options', Combobox.Options], + ['Combobox.Option', Combobox.Option], + ])( + 'should error when we are using a <%s /> without a parent ', + suppressConsoleLogs((name, Component) => { + // @ts-expect-error This is fine + expect(() => render(createElement(Component))).toThrowError( + `<${name} /> is missing a parent component.` + ) + }) + ) + + it( + 'should be possible to render a Combobox without crashing', + suppressConsoleLogs(async () => { + render( + + + Trigger + + Option A + Option B + Option C + + + ) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + }) + ) +}) + +describe('Rendering', () => { + describe('Combobox', () => { + it( + 'should be possible to render a Combobox using a render prop', + suppressConsoleLogs(async () => { + render( + + {({ open }) => ( + <> + + Trigger + {open && ( + + Option A + Option B + Option C + + )} + + )} + + ) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + await click(getComboboxButton()) + + assertComboboxButton({ + state: ComboboxState.Visible, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.Visible }) + }) + ) + + it( + 'should be possible to disable a Combobox', + suppressConsoleLogs(async () => { + render( + + + Trigger + + Option A + Option B + Option C + + + ) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + await click(getComboboxButton()) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + await press(Keys.Enter, getComboboxButton()) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + }) + ) + }) + + describe('Combobox.Input', () => { + it( + 'selecting an option puts the value into Combobox.Input when displayValue is not provided', + suppressConsoleLogs(async () => { + function Example() { + let [value, setValue] = useState(undefined) + + return ( + + + Trigger + + Option A + Option B + Option C + + + ) + } + + render() + + await click(getComboboxButton()) + + assertComboboxList({ state: ComboboxState.Visible }) + + await click(getComboboxOptions()[1]) + + expect(getComboboxInput()).toHaveValue('b') + }) + ) + + it( + 'selecting an option puts the display value into Combobox.Input when displayValue is provided', + suppressConsoleLogs(async () => { + function Example() { + let [value, setValue] = useState(undefined) + + return ( + + str?.toUpperCase() ?? ''} + /> + Trigger + + Option A + Option B + Option C + + + ) + } + + render() + + await click(getComboboxButton()) + + assertComboboxList({ state: ComboboxState.Visible }) + + await click(getComboboxOptions()[1]) + + expect(getComboboxInput()).toHaveValue('B') + }) + ) + }) + + describe('Combobox.Label', () => { + it( + 'should be possible to render a Combobox.Label using a render prop', + suppressConsoleLogs(async () => { + render( + + {JSON.stringify} + + Trigger + + Option A + Option B + Option C + + + ) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-3' }, + }) + assertComboboxLabel({ + attributes: { id: 'headlessui-combobox-label-1' }, + textContent: JSON.stringify({ open: false, disabled: false }), + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + await click(getComboboxButton()) + + assertComboboxLabel({ + attributes: { id: 'headlessui-combobox-label-1' }, + textContent: JSON.stringify({ open: true, disabled: false }), + }) + assertComboboxList({ state: ComboboxState.Visible }) + assertComboboxLabelLinkedWithCombobox() + assertComboboxButtonLinkedWithComboboxLabel() + }) + ) + + it( + 'should be possible to render a Combobox.Label using a render prop and an `as` prop', + suppressConsoleLogs(async () => { + render( + + {JSON.stringify} + + Trigger + + Option A + Option B + Option C + + + ) + + assertComboboxLabel({ + attributes: { id: 'headlessui-combobox-label-1' }, + textContent: JSON.stringify({ open: false, disabled: false }), + tag: 'p', + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + await click(getComboboxButton()) + assertComboboxLabel({ + attributes: { id: 'headlessui-combobox-label-1' }, + textContent: JSON.stringify({ open: true, disabled: false }), + tag: 'p', + }) + assertComboboxList({ state: ComboboxState.Visible }) + }) + ) + }) + + describe('Combobox.Button', () => { + it( + 'should be possible to render a Combobox.Button using a render prop', + suppressConsoleLogs(async () => { + render( + + + {JSON.stringify} + + Option A + Option B + Option C + + + ) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + textContent: JSON.stringify({ open: false, disabled: false }), + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + await click(getComboboxButton()) + + assertComboboxButton({ + state: ComboboxState.Visible, + attributes: { id: 'headlessui-combobox-button-2' }, + textContent: JSON.stringify({ open: true, disabled: false }), + }) + assertComboboxList({ state: ComboboxState.Visible }) + }) + ) + + it( + 'should be possible to render a Combobox.Button using a render prop and an `as` prop', + suppressConsoleLogs(async () => { + render( + + + + {JSON.stringify} + + + Option A + Option B + Option C + + + ) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + textContent: JSON.stringify({ open: false, disabled: false }), + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + await click(getComboboxButton()) + + assertComboboxButton({ + state: ComboboxState.Visible, + attributes: { id: 'headlessui-combobox-button-2' }, + textContent: JSON.stringify({ open: true, disabled: false }), + }) + assertComboboxList({ state: ComboboxState.Visible }) + }) + ) + + it( + 'should be possible to render a Combobox.Button and a Combobox.Label and see them linked together', + suppressConsoleLogs(async () => { + render( + + Label + + Trigger + + Option A + Option B + Option C + + + ) + + // TODO: Needed to make it similar to vue test implementation? + // await new Promise(requestAnimationFrame) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-3' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + assertComboboxButtonLinkedWithComboboxLabel() + }) + ) + + describe('`type` attribute', () => { + it('should set the `type` to "button" by default', async () => { + render( + + + Trigger + + ) + + expect(getComboboxButton()).toHaveAttribute('type', 'button') + }) + + it('should not set the `type` to "button" if it already contains a `type`', async () => { + render( + + + Trigger + + ) + + expect(getComboboxButton()).toHaveAttribute('type', 'submit') + }) + + it('should set the `type` to "button" when using the `as` prop which resolves to a "button"', async () => { + let CustomButton = React.forwardRef((props, ref) => ( + + + ) + + // Click the combobox button + await click(getComboboxButton()) + + // Ensure the combobox is open + assertComboboxList({ state: ComboboxState.Visible }) + + // Click the span inside the button + await click(getByText('Next')) + + // Ensure the combobox is closed + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Ensure the outside button is focused + assertActiveElement(document.getElementById('btn')) + + // Ensure that the focus button only got focus once (first click) + expect(focusFn).toHaveBeenCalledTimes(1) + }) + ) + + it( + 'should be possible to hover an option and make it active', + suppressConsoleLogs(async () => { + render( + + + Trigger + + alice + bob + charlie + + + ) + + // Open combobox + await click(getComboboxButton()) + + let options = getComboboxOptions() + // We should be able to go to the second option + await mouseMove(options[1]) + assertActiveComboboxOption(options[1]) + + // We should be able to go to the first option + await mouseMove(options[0]) + assertActiveComboboxOption(options[0]) + + // We should be able to go to the last option + await mouseMove(options[2]) + assertActiveComboboxOption(options[2]) + }) + ) + + it( + 'should make a combobox option active when you move the mouse over it', + suppressConsoleLogs(async () => { + render( + + + Trigger + + alice + bob + charlie + + + ) + + // Open combobox + await click(getComboboxButton()) + + let options = getComboboxOptions() + // We should be able to go to the second option + await mouseMove(options[1]) + assertActiveComboboxOption(options[1]) + }) + ) + + it( + 'should be a no-op when we move the mouse and the combobox option is already active', + suppressConsoleLogs(async () => { + render( + + + Trigger + + alice + bob + charlie + + + ) + + // Open combobox + await click(getComboboxButton()) + + let options = getComboboxOptions() + + // We should be able to go to the second option + await mouseMove(options[1]) + assertActiveComboboxOption(options[1]) + + await mouseMove(options[1]) + + // Nothing should be changed + assertActiveComboboxOption(options[1]) + }) + ) + + it( + 'should be a no-op when we move the mouse and the combobox option is disabled', + suppressConsoleLogs(async () => { + render( + + + Trigger + + alice + + bob + + charlie + + + ) + + // Open combobox + await click(getComboboxButton()) + + let options = getComboboxOptions() + + await mouseMove(options[1]) + assertNoActiveComboboxOption() + }) + ) + + it( + 'should not be possible to hover an option that is disabled', + suppressConsoleLogs(async () => { + render( + + + Trigger + + alice + + bob + + charlie + + + ) + + // Open combobox + await click(getComboboxButton()) + + let options = getComboboxOptions() + + // Try to hover over option 1, which is disabled + await mouseMove(options[1]) + + // We should not have an active option now + assertNoActiveComboboxOption() + }) + ) + + it( + 'should be possible to mouse leave an option and make it inactive', + suppressConsoleLogs(async () => { + render( + + + Trigger + + alice + bob + charlie + + + ) + + // Open combobox + await click(getComboboxButton()) + + let options = getComboboxOptions() + + // We should be able to go to the second option + await mouseMove(options[1]) + assertActiveComboboxOption(options[1]) + + await mouseLeave(options[1]) + assertNoActiveComboboxOption() + + // We should be able to go to the first option + await mouseMove(options[0]) + assertActiveComboboxOption(options[0]) + + await mouseLeave(options[0]) + assertNoActiveComboboxOption() + + // We should be able to go to the last option + await mouseMove(options[2]) + assertActiveComboboxOption(options[2]) + + await mouseLeave(options[2]) + assertNoActiveComboboxOption() + }) + ) + + it( + 'should be possible to mouse leave a disabled option and be a no-op', + suppressConsoleLogs(async () => { + render( + + + Trigger + + alice + + bob + + charlie + + + ) + + // Open combobox + await click(getComboboxButton()) + + let options = getComboboxOptions() + + // Try to hover over option 1, which is disabled + await mouseMove(options[1]) + assertNoActiveComboboxOption() + + await mouseLeave(options[1]) + assertNoActiveComboboxOption() + }) + ) + + it( + 'should be possible to click a combobox option, which closes the combobox', + suppressConsoleLogs(async () => { + let handleChange = jest.fn() + function Example() { + let [value, setValue] = useState(undefined) + + return ( + { + setValue(value) + handleChange(value) + }} + > + + Trigger + + alice + bob + charlie + + + ) + } + + render() + + // Open combobox + await click(getComboboxButton()) + assertComboboxList({ state: ComboboxState.Visible }) + assertActiveElement(getComboboxInput()) + + let options = getComboboxOptions() + + // We should be able to click the first option + await click(options[1]) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + expect(handleChange).toHaveBeenCalledTimes(1) + expect(handleChange).toHaveBeenCalledWith('bob') + + // Verify the input is focused again + assertActiveElement(getComboboxInput()) + + // Open combobox again + await click(getComboboxButton()) + + // Verify the active option is the previously selected one + assertActiveComboboxOption(getComboboxOptions()[1]) + }) + ) + + it( + 'should be possible to click a disabled combobox option, which is a no-op', + suppressConsoleLogs(async () => { + let handleChange = jest.fn() + function Example() { + let [value, setValue] = useState(undefined) + + return ( + { + setValue(value) + handleChange(value) + }} + > + + Trigger + + alice + + bob + + charlie + + + ) + } + + render() + + // Open combobox + await click(getComboboxButton()) + assertComboboxList({ state: ComboboxState.Visible }) + assertActiveElement(getComboboxInput()) + + let options = getComboboxOptions() + + // We should be able to click the first option + await click(options[1]) + assertComboboxList({ state: ComboboxState.Visible }) + assertActiveElement(getComboboxInput()) + expect(handleChange).toHaveBeenCalledTimes(0) + + // Close the combobox + await click(getComboboxButton()) + + // Open combobox again + await click(getComboboxButton()) + + // Verify the active option is non existing + assertNoActiveComboboxOption() + }) + ) + + it( + 'should be possible focus a combobox option, so that it becomes active', + suppressConsoleLogs(async () => { + function Example() { + let [value, setValue] = useState(undefined) + + return ( + + + Trigger + + alice + bob + charlie + + + ) + } + + render() + + // Open combobox + await click(getComboboxButton()) + assertComboboxList({ state: ComboboxState.Visible }) + assertActiveElement(getComboboxInput()) + + let options = getComboboxOptions() + + // Verify that nothing is active yet + assertNoActiveComboboxOption() + + // We should be able to focus the first option + await focus(options[1]) + assertActiveComboboxOption(options[1]) + }) + ) + + it( + 'should not be possible to focus a combobox option which is disabled', + suppressConsoleLogs(async () => { + render( + + + Trigger + + alice + + bob + + charlie + + + ) + + // Open combobox + await click(getComboboxButton()) + assertComboboxList({ state: ComboboxState.Visible }) + assertActiveElement(getComboboxInput()) + + let options = getComboboxOptions() + + // We should not be able to focus the first option + await focus(options[1]) + assertNoActiveComboboxOption() + }) + ) +}) diff --git a/packages/@headlessui-react/src/components/combobox/combobox.tsx b/packages/@headlessui-react/src/components/combobox/combobox.tsx new file mode 100644 index 0000000000..614113221a --- /dev/null +++ b/packages/@headlessui-react/src/components/combobox/combobox.tsx @@ -0,0 +1,925 @@ +import React, { + Fragment, + createContext, + createRef, + useCallback, + useContext, + useMemo, + useReducer, + useRef, + + // Types + Dispatch, + ElementType, + KeyboardEvent as ReactKeyboardEvent, + MouseEvent as ReactMouseEvent, + MutableRefObject, + Ref, + ContextType, +} from 'react' + +import { useDisposables } from '../../hooks/use-disposables' +import { useId } from '../../hooks/use-id' +import { useIsoMorphicEffect } from '../../hooks/use-iso-morphic-effect' +import { useComputed } from '../../hooks/use-computed' +import { useSyncRefs } from '../../hooks/use-sync-refs' +import { Props } from '../../types' +import { Features, forwardRefWithAs, PropsForFeatures, render } from '../../utils/render' +import { match } from '../../utils/match' +import { disposables } from '../../utils/disposables' +import { Keys } from '../keyboard' +import { Focus, calculateActiveIndex } from '../../utils/calculate-active-index' +import { isDisabledReactIssue7711 } from '../../utils/bugs' +import { isFocusableElement, FocusableMode } from '../../utils/focus-management' +import { useWindowEvent } from '../../hooks/use-window-event' +import { useOpenClosed, State, OpenClosedProvider } from '../../internal/open-closed' +import { useResolveButtonType } from '../../hooks/use-resolve-button-type' +import { useLatestValue } from '../../hooks/use-latest-value' + +enum ComboboxStates { + Open, + Closed, +} + +type ComboboxOptionDataRef = MutableRefObject<{ + textValue?: string + disabled: boolean + value: unknown +}> + +interface StateDefinition { + comboboxState: ComboboxStates + + orientation: 'horizontal' | 'vertical' + + propsRef: MutableRefObject<{ + value: unknown + onChange(value: unknown): void + }> + inputPropsRef: MutableRefObject<{ + displayValue?(item: unknown): string + }> + labelRef: MutableRefObject + inputRef: MutableRefObject + buttonRef: MutableRefObject + optionsRef: MutableRefObject + + disabled: boolean + options: { id: string; dataRef: ComboboxOptionDataRef }[] + activeOptionIndex: number | null +} + +enum ActionTypes { + OpenCombobox, + CloseCombobox, + + SetDisabled, + SetOrientation, + + GoToOption, + + RegisterOption, + UnregisterOption, +} + +type Actions = + | { type: ActionTypes.CloseCombobox } + | { type: ActionTypes.OpenCombobox } + | { type: ActionTypes.SetDisabled; disabled: boolean } + | { type: ActionTypes.SetOrientation; orientation: StateDefinition['orientation'] } + | { type: ActionTypes.GoToOption; focus: Focus.Specific; id: string } + | { type: ActionTypes.GoToOption; focus: Exclude } + | { type: ActionTypes.RegisterOption; id: string; dataRef: ComboboxOptionDataRef } + | { type: ActionTypes.UnregisterOption; id: string } + +let reducers: { + [P in ActionTypes]: ( + state: StateDefinition, + action: Extract + ) => StateDefinition +} = { + [ActionTypes.CloseCombobox](state) { + if (state.disabled) return state + if (state.comboboxState === ComboboxStates.Closed) return state + return { ...state, activeOptionIndex: null, comboboxState: ComboboxStates.Closed } + }, + [ActionTypes.OpenCombobox](state) { + if (state.disabled) return state + if (state.comboboxState === ComboboxStates.Open) return state + return { ...state, comboboxState: ComboboxStates.Open } + }, + [ActionTypes.SetDisabled](state, action) { + if (state.disabled === action.disabled) return state + return { ...state, disabled: action.disabled } + }, + [ActionTypes.SetOrientation](state, action) { + if (state.orientation === action.orientation) return state + return { ...state, orientation: action.orientation } + }, + [ActionTypes.GoToOption](state, action) { + if (state.disabled) return state + if (state.comboboxState === ComboboxStates.Closed) return state + + let activeOptionIndex = calculateActiveIndex(action, { + resolveItems: () => state.options, + resolveActiveIndex: () => state.activeOptionIndex, + resolveId: (item) => item.id, + resolveDisabled: (item) => item.dataRef.current.disabled, + }) + + if (state.activeOptionIndex === activeOptionIndex) return state + return { ...state, activeOptionIndex } + }, + [ActionTypes.RegisterOption]: (state, action) => { + let currentActiveOption = + state.activeOptionIndex !== null ? state.options[state.activeOptionIndex] : null + + let orderMap = Array.from( + state.optionsRef.current?.querySelectorAll('[id^="headlessui-combobox-option-"]')! + ).reduce( + (lookup, element, index) => Object.assign(lookup, { [element.id]: index }), + {} + ) as Record + + let options = [...state.options, { id: action.id, dataRef: action.dataRef }].sort( + (a, z) => orderMap[a.id] - orderMap[z.id] + ) + + return { + ...state, + options, + activeOptionIndex: (() => { + if (currentActiveOption === null) return null + + // If we inserted an option before the current active option then the + // active option index would be wrong. To fix this, we will re-lookup + // the correct index. + return options.indexOf(currentActiveOption) + })(), + } + }, + [ActionTypes.UnregisterOption]: (state, action) => { + let nextOptions = state.options.slice() + let currentActiveOption = + state.activeOptionIndex !== null ? nextOptions[state.activeOptionIndex] : null + + let idx = nextOptions.findIndex((a) => a.id === action.id) + + if (idx !== -1) nextOptions.splice(idx, 1) + + return { + ...state, + options: nextOptions, + activeOptionIndex: (() => { + if (idx === state.activeOptionIndex) return null + if (currentActiveOption === null) return null + + // If we removed the option before the actual active index, then it would be out of sync. To + // fix this, we will find the correct (new) index position. + return nextOptions.indexOf(currentActiveOption) + })(), + } + }, +} + +let ComboboxContext = createContext<[StateDefinition, Dispatch] | null>(null) +ComboboxContext.displayName = 'ComboboxContext' + +function useComboboxContext(component: string) { + let context = useContext(ComboboxContext) + if (context === null) { + let err = new Error(`<${component} /> is missing a parent <${Combobox.name} /> component.`) + if (Error.captureStackTrace) Error.captureStackTrace(err, useComboboxContext) + throw err + } + return context +} + +let ComboboxActions = createContext<{ + selectOption(id: string): void + selectActiveOption(): void +} | null>(null) +ComboboxActions.displayName = 'ComboboxActions' + +function useComboboxActions() { + let context = useContext(ComboboxActions) + if (context === null) { + let err = new Error(`ComboboxActions is missing a parent <${Combobox.name} /> component.`) + if (Error.captureStackTrace) Error.captureStackTrace(err, useComboboxActions) + throw err + } + return context +} + +function stateReducer(state: StateDefinition, action: Actions) { + return match(action.type, reducers, state, action) +} + +// --- + +let DEFAULT_COMBOBOX_TAG = Fragment +interface ComboboxRenderPropArg { + open: boolean + disabled: boolean + activeIndex: number | null + activeOption: T | null +} + +export function Combobox( + props: Props< + TTag, + ComboboxRenderPropArg, + 'value' | 'onChange' | 'disabled' | 'horizontal' + > & { + value: TType + onChange(value: TType): void + disabled?: boolean + horizontal?: boolean + } +) { + let { value, onChange, disabled = false, horizontal = false, ...passThroughProps } = props + const orientation = horizontal ? 'horizontal' : 'vertical' + + let reducerBag = useReducer(stateReducer, { + comboboxState: ComboboxStates.Closed, + propsRef: { + current: { + value, + onChange, + }, + }, + inputPropsRef: { + current: { + displayValue: undefined, + }, + }, + labelRef: createRef(), + inputRef: createRef(), + buttonRef: createRef(), + optionsRef: createRef(), + disabled, + orientation, + options: [], + activeOptionIndex: null, + } as StateDefinition) + let [ + { + comboboxState, + options, + activeOptionIndex, + propsRef, + inputPropsRef, + optionsRef, + inputRef, + buttonRef, + }, + dispatch, + ] = reducerBag + + useIsoMorphicEffect(() => { + propsRef.current.value = value + }, [value, propsRef]) + useIsoMorphicEffect(() => { + propsRef.current.onChange = onChange + }, [onChange, propsRef]) + + useIsoMorphicEffect(() => dispatch({ type: ActionTypes.SetDisabled, disabled }), [disabled]) + useIsoMorphicEffect( + () => dispatch({ type: ActionTypes.SetOrientation, orientation }), + [orientation] + ) + + // Handle outside click + useWindowEvent('mousedown', (event) => { + let target = event.target as HTMLElement + + if (comboboxState !== ComboboxStates.Open) return + + if (buttonRef.current?.contains(target)) return + if (inputRef.current?.contains(target)) return + if (optionsRef.current?.contains(target)) return + + dispatch({ type: ActionTypes.CloseCombobox }) + + if (!isFocusableElement(target, FocusableMode.Loose)) { + event.preventDefault() + inputRef.current?.focus() + } + }) + + let slot = useMemo>( + () => ({ + open: comboboxState === ComboboxStates.Open, + disabled, + activeIndex: activeOptionIndex, + activeOption: + activeOptionIndex === null + ? null + : (options[activeOptionIndex].dataRef.current.value as TType), + }), + [comboboxState, disabled, options, activeOptionIndex] + ) + + let syncInputValue = useCallback(() => { + if (!inputRef.current) return + if (value === undefined) return + let displayValue = inputPropsRef.current.displayValue + + if (typeof displayValue === 'function') { + inputRef.current.value = displayValue(value) + } else if (typeof value === 'string') { + inputRef.current.value = value + } + }, [value, inputRef, inputPropsRef]) + + let selectOption = useCallback( + (id: string) => { + let option = options.find((item) => item.id === id) + if (!option) return + + let { dataRef } = option + propsRef.current.onChange(dataRef.current.value) + syncInputValue() + }, + [options, propsRef, inputRef] + ) + + let selectActiveOption = useCallback(() => { + if (activeOptionIndex !== null) { + let { dataRef } = options[activeOptionIndex] + propsRef.current.onChange(dataRef.current.value) + syncInputValue() + } + }, [activeOptionIndex, options, propsRef, inputRef]) + + let actionsBag = useMemo>( + () => ({ selectOption, selectActiveOption }), + [selectOption, selectActiveOption] + ) + + useIsoMorphicEffect(() => { + if (comboboxState !== ComboboxStates.Closed) { + return + } + syncInputValue() + }, [syncInputValue, comboboxState]) + + // Ensure that we update the inputRef if the value changes + useIsoMorphicEffect(syncInputValue, [syncInputValue]) + + return ( + + + + {render({ + props: passThroughProps, + slot, + defaultTag: DEFAULT_COMBOBOX_TAG, + name: 'Combobox', + })} + + + + ) +} + +// --- + +let DEFAULT_INPUT_TAG = 'input' as const +interface InputRenderPropArg { + open: boolean + disabled: boolean +} +type InputPropsWeControl = + | 'id' + | 'role' + | 'type' + | 'aria-labelledby' + | 'aria-expanded' + | 'aria-activedescendant' + | 'onKeyDown' + | 'onChange' + | 'displayValue' + +let Input = forwardRefWithAs(function Input< + TTag extends ElementType = typeof DEFAULT_INPUT_TAG, + // TODO: One day we will be able to infer this type from the generic in Combobox itself. + // But today is not that day.. + TType = Parameters[0]['value'] +>( + props: Props & { + displayValue?(item: TType): string + onChange(event: React.ChangeEvent): void + }, + ref: Ref +) { + let { value, onChange, displayValue, ...passThroughProps } = props + let [state, dispatch] = useComboboxContext('Combobox.Input') + let actions = useComboboxActions() + + let inputRef = useSyncRefs(state.inputRef, ref) + let inputPropsRef = state.inputPropsRef + + let id = `headlessui-combobox-input-${useId()}` + let d = useDisposables() + + let onChangeRef = useLatestValue(onChange) + + useIsoMorphicEffect(() => { + inputPropsRef.current.displayValue = displayValue + }, [displayValue, inputPropsRef]) + + let handleKeyDown = useCallback( + (event: ReactKeyboardEvent) => { + switch (event.key) { + // Ref: https://www.w3.org/TR/wai-aria-practices-1.2/#keyboard-interaction-12 + + case Keys.Enter: + event.preventDefault() + event.stopPropagation() + + actions.selectActiveOption() + dispatch({ type: ActionTypes.CloseCombobox }) + break + + case match(state.orientation, { vertical: Keys.ArrowDown, horizontal: Keys.ArrowRight }): + event.preventDefault() + event.stopPropagation() + return match(state.comboboxState, { + [ComboboxStates.Open]: () => { + return dispatch({ type: ActionTypes.GoToOption, focus: Focus.Next }) + }, + [ComboboxStates.Closed]: () => { + dispatch({ type: ActionTypes.OpenCombobox }) + // TODO: We can't do this outside next frame because the options aren't rendered yet + // But doing this in next frame results in a flicker because the dom mutations are async here + // Basically: + // Sync -> no option list yet + // Next frame -> option list already rendered with selection -> dispatch -> next frame -> now we have the focus on the right element + + // TODO: The spec here is underspecified. There's mention of skipping to the next item when autocomplete has suggested something but nothing regarding a non-autocomplete selection/value + d.nextFrame(() => { + if (!state.propsRef.current.value) { + dispatch({ type: ActionTypes.GoToOption, focus: Focus.First }) + } + }) + }, + }) + + case match(state.orientation, { vertical: Keys.ArrowUp, horizontal: Keys.ArrowLeft }): + event.preventDefault() + event.stopPropagation() + return match(state.comboboxState, { + [ComboboxStates.Open]: () => { + return dispatch({ type: ActionTypes.GoToOption, focus: Focus.Previous }) + }, + [ComboboxStates.Closed]: () => { + dispatch({ type: ActionTypes.OpenCombobox }) + d.nextFrame(() => { + if (!state.propsRef.current.value) { + dispatch({ type: ActionTypes.GoToOption, focus: Focus.Last }) + } + }) + }, + }) + + case Keys.Home: + case Keys.PageUp: + event.preventDefault() + event.stopPropagation() + return dispatch({ type: ActionTypes.GoToOption, focus: Focus.First }) + + case Keys.End: + case Keys.PageDown: + event.preventDefault() + event.stopPropagation() + return dispatch({ type: ActionTypes.GoToOption, focus: Focus.Last }) + + case Keys.Escape: + event.preventDefault() + event.stopPropagation() + return dispatch({ type: ActionTypes.CloseCombobox }) + + case Keys.Tab: + actions.selectActiveOption() + dispatch({ type: ActionTypes.CloseCombobox }) + break + } + }, + [d, dispatch, state, actions] + ) + + let handleChange = useCallback( + (event: React.ChangeEvent) => { + dispatch({ type: ActionTypes.OpenCombobox }) + onChangeRef.current(event) + }, + [dispatch, onChangeRef] + ) + + // TODO: Verify this. The spec says that, for the input/combobox, the lebel is the labelling element when present + // Otherwise it's the ID of the non-label element + let labelledby = useComputed(() => { + if (!state.labelRef.current) return undefined + return [state.labelRef.current.id].join(' ') + }, [state.labelRef.current]) + + let slot = useMemo( + () => ({ open: state.comboboxState === ComboboxStates.Open, disabled: state.disabled }), + [state] + ) + + let propsWeControl = { + ref: inputRef, + id, + role: 'combobox', + type: 'text', + 'aria-controls': state.optionsRef.current?.id, + 'aria-expanded': state.disabled ? undefined : state.comboboxState === ComboboxStates.Open, + 'aria-activedescendant': + state.activeOptionIndex === null ? undefined : state.options[state.activeOptionIndex]?.id, + 'aria-labelledby': labelledby, + disabled: state.disabled, + onKeyDown: handleKeyDown, + onChange: handleChange, + } + + return render({ + props: { ...passThroughProps, ...propsWeControl }, + slot, + defaultTag: DEFAULT_INPUT_TAG, + name: 'Combobox.Input', + }) +}) + +// --- + +let DEFAULT_BUTTON_TAG = 'button' as const +interface ButtonRenderPropArg { + open: boolean + disabled: boolean +} +type ButtonPropsWeControl = + | 'id' + | 'type' + | 'tabIndex' + | 'aria-haspopup' + | 'aria-controls' + | 'aria-expanded' + | 'aria-labelledby' + | 'disabled' + | 'onClick' + | 'onKeyDown' + +let Button = forwardRefWithAs(function Button( + props: Props, + ref: Ref +) { + let [state, dispatch] = useComboboxContext('Combobox.Button') + let actions = useComboboxActions() + let buttonRef = useSyncRefs(state.buttonRef, ref) + + let id = `headlessui-combobox-button-${useId()}` + let d = useDisposables() + + let handleKeyDown = useCallback( + (event: ReactKeyboardEvent) => { + switch (event.key) { + // Ref: https://www.w3.org/TR/wai-aria-practices-1.2/#keyboard-interaction-12 + + case match(state.orientation, { vertical: Keys.ArrowDown, horizontal: Keys.ArrowRight }): + event.preventDefault() + event.stopPropagation() + if (state.comboboxState === ComboboxStates.Closed) { + dispatch({ type: ActionTypes.OpenCombobox }) + // TODO: We can't do this outside next frame because the options aren't rendered yet + // But doing this in next frame results in a flicker because the dom mutations are async here + // Basically: + // Sync -> no option list yet + // Next frame -> option list already rendered with selection -> dispatch -> next frame -> now we have the focus on the right element + + // TODO: The spec here is underspecified. There's mention of skipping to the next item when autocomplete has suggested something but nothing regarding a non-autocomplete selection/value + d.nextFrame(() => { + if (!state.propsRef.current.value) { + dispatch({ type: ActionTypes.GoToOption, focus: Focus.First }) + } + }) + } + return d.nextFrame(() => state.inputRef.current?.focus({ preventScroll: true })) + + case match(state.orientation, { vertical: Keys.ArrowUp, horizontal: Keys.ArrowLeft }): + event.preventDefault() + event.stopPropagation() + if (state.comboboxState === ComboboxStates.Closed) { + dispatch({ type: ActionTypes.OpenCombobox }) + d.nextFrame(() => { + if (!state.propsRef.current.value) { + dispatch({ type: ActionTypes.GoToOption, focus: Focus.Last }) + } + }) + } + return d.nextFrame(() => state.inputRef.current?.focus({ preventScroll: true })) + + case Keys.Escape: + event.preventDefault() + event.stopPropagation() + dispatch({ type: ActionTypes.CloseCombobox }) + return d.nextFrame(() => state.inputRef.current?.focus({ preventScroll: true })) + } + }, + [d, dispatch, state, actions] + ) + + let handleClick = useCallback( + (event: ReactMouseEvent) => { + if (isDisabledReactIssue7711(event.currentTarget)) return event.preventDefault() + if (state.comboboxState === ComboboxStates.Open) { + dispatch({ type: ActionTypes.CloseCombobox }) + } else { + event.preventDefault() + dispatch({ type: ActionTypes.OpenCombobox }) + } + + d.nextFrame(() => state.inputRef.current?.focus({ preventScroll: true })) + }, + [dispatch, d, state] + ) + + let labelledby = useComputed(() => { + if (!state.labelRef.current) return undefined + return [state.labelRef.current.id, id].join(' ') + }, [state.labelRef.current, id]) + + let slot = useMemo( + () => ({ open: state.comboboxState === ComboboxStates.Open, disabled: state.disabled }), + [state] + ) + let passthroughProps = props + let propsWeControl = { + ref: buttonRef, + id, + type: useResolveButtonType(props, state.buttonRef), + tabIndex: -1, + 'aria-haspopup': true, + 'aria-controls': state.optionsRef.current?.id, + 'aria-expanded': state.disabled ? undefined : state.comboboxState === ComboboxStates.Open, + 'aria-labelledby': labelledby, + disabled: state.disabled, + onClick: handleClick, + onKeyDown: handleKeyDown, + } + + return render({ + props: { ...passthroughProps, ...propsWeControl }, + slot, + defaultTag: DEFAULT_BUTTON_TAG, + name: 'Combobox.Button', + }) +}) + +// --- + +let DEFAULT_LABEL_TAG = 'label' as const +interface LabelRenderPropArg { + open: boolean + disabled: boolean +} +type LabelPropsWeControl = 'id' | 'ref' | 'onClick' + +function Label( + props: Props +) { + let [state] = useComboboxContext('Combobox.Label') + let id = `headlessui-combobox-label-${useId()}` + + let handleClick = useCallback( + () => state.inputRef.current?.focus({ preventScroll: true }), + [state.inputRef] + ) + + let slot = useMemo( + () => ({ open: state.comboboxState === ComboboxStates.Open, disabled: state.disabled }), + [state] + ) + let propsWeControl = { ref: state.labelRef, id, onClick: handleClick } + return render({ + props: { ...props, ...propsWeControl }, + slot, + defaultTag: DEFAULT_LABEL_TAG, + name: 'Combobox.Label', + }) +} + +// --- + +let DEFAULT_OPTIONS_TAG = 'ul' as const +interface OptionsRenderPropArg { + open: boolean +} +type OptionsPropsWeControl = + | 'aria-activedescendant' + | 'aria-labelledby' + | 'aria-orientation' + | 'id' + | 'onKeyDown' + | 'role' + | 'tabIndex' + +let OptionsRenderFeatures = Features.RenderStrategy | Features.Static + +let Options = forwardRefWithAs(function Options< + TTag extends ElementType = typeof DEFAULT_OPTIONS_TAG +>( + props: Props & + PropsForFeatures, + ref: Ref +) { + let [state, dispatch] = useComboboxContext('Combobox.Options') + let optionsRef = useSyncRefs(state.optionsRef, ref) + + let id = `headlessui-combobox-options-${useId()}` + + let usesOpenClosedState = useOpenClosed() + let visible = (() => { + if (usesOpenClosedState !== null) { + return usesOpenClosedState === State.Open + } + + return state.comboboxState === ComboboxStates.Open + })() + + let labelledby = useComputed( + () => state.labelRef.current?.id ?? state.buttonRef.current?.id, + [state.labelRef.current, state.buttonRef.current] + ) + + let handleLeave = useCallback(() => { + if (state.comboboxState !== ComboboxStates.Open) return + if (state.activeOptionIndex === null) return + dispatch({ type: ActionTypes.GoToOption, focus: Focus.Nothing }) + }, [state, dispatch]) + + let slot = useMemo( + () => ({ open: state.comboboxState === ComboboxStates.Open }), + [state] + ) + let propsWeControl = { + 'aria-activedescendant': + state.activeOptionIndex === null ? undefined : state.options[state.activeOptionIndex]?.id, + 'aria-labelledby': labelledby, + 'aria-orientation': state.orientation, + role: 'listbox', + id, + ref: optionsRef, + onPointerLeave: handleLeave, + onMouseLeave: handleLeave, + } + let passthroughProps = props + + return render({ + props: { ...passthroughProps, ...propsWeControl }, + slot, + defaultTag: DEFAULT_OPTIONS_TAG, + features: OptionsRenderFeatures, + visible, + name: 'Combobox.Options', + }) +}) + +// --- + +let DEFAULT_OPTION_TAG = 'li' as const +interface OptionRenderPropArg { + active: boolean + selected: boolean + disabled: boolean +} +type ComboboxOptionPropsWeControl = + | 'id' + | 'role' + | 'tabIndex' + | 'aria-disabled' + | 'aria-selected' + | 'onPointerLeave' + | 'onMouseLeave' + | 'onPointerMove' + | 'onMouseMove' + +function Option< + TTag extends ElementType = typeof DEFAULT_OPTION_TAG, + // TODO: One day we will be able to infer this type from the generic in Combobox itself. + // But today is not that day.. + TType = Parameters[0]['value'] +>( + props: Props & { + disabled?: boolean + value: TType + } +) { + let { disabled = false, value, ...passthroughProps } = props + let [state, dispatch] = useComboboxContext('Combobox.Option') + let actions = useComboboxActions() + let id = `headlessui-combobox-option-${useId()}` + let active = + state.activeOptionIndex !== null ? state.options[state.activeOptionIndex].id === id : false + let selected = state.propsRef.current.value === value + let bag = useRef({ disabled, value }) + + useIsoMorphicEffect(() => { + bag.current.disabled = disabled + }, [bag, disabled]) + useIsoMorphicEffect(() => { + bag.current.value = value + }, [bag, value]) + useIsoMorphicEffect(() => { + bag.current.textValue = document.getElementById(id)?.textContent?.toLowerCase() + }, [bag, id]) + + let select = useCallback(() => actions.selectOption(id), [actions, id]) + + useIsoMorphicEffect(() => { + dispatch({ type: ActionTypes.RegisterOption, id, dataRef: bag }) + return () => dispatch({ type: ActionTypes.UnregisterOption, id }) + }, [bag, id]) + + useIsoMorphicEffect(() => { + if (state.comboboxState !== ComboboxStates.Open) return + if (!selected) return + dispatch({ type: ActionTypes.GoToOption, focus: Focus.Specific, id }) + }, [state.comboboxState]) + + useIsoMorphicEffect(() => { + if (state.comboboxState !== ComboboxStates.Open) return + if (!active) return + let d = disposables() + d.nextFrame(() => document.getElementById(id)?.scrollIntoView?.({ block: 'nearest' })) + return d.dispose + }, [id, active, state.comboboxState]) + + let handleClick = useCallback( + (event: { preventDefault: Function }) => { + if (disabled) return event.preventDefault() + select() + dispatch({ type: ActionTypes.CloseCombobox }) + disposables().nextFrame(() => state.inputRef.current?.focus({ preventScroll: true })) + }, + [dispatch, state.inputRef, disabled, select] + ) + + let handleFocus = useCallback(() => { + if (disabled) return dispatch({ type: ActionTypes.GoToOption, focus: Focus.Nothing }) + dispatch({ type: ActionTypes.GoToOption, focus: Focus.Specific, id }) + }, [disabled, id, dispatch]) + + let handleMove = useCallback(() => { + if (disabled) return + if (active) return + dispatch({ type: ActionTypes.GoToOption, focus: Focus.Specific, id }) + }, [disabled, active, id, dispatch]) + + let handleLeave = useCallback(() => { + if (disabled) return + if (!active) return + dispatch({ type: ActionTypes.GoToOption, focus: Focus.Nothing }) + }, [disabled, active, dispatch]) + + let slot = useMemo( + () => ({ active, selected, disabled }), + [active, selected, disabled] + ) + + let propsWeControl = { + id, + role: 'option', + tabIndex: disabled === true ? undefined : -1, + 'aria-disabled': disabled === true ? true : undefined, + 'aria-selected': selected === true ? true : undefined, + disabled: undefined, // Never forward the `disabled` prop + onClick: handleClick, + onFocus: handleFocus, + onPointerMove: handleMove, + onMouseMove: handleMove, + onPointerLeave: handleLeave, + onMouseLeave: handleLeave, + } + + return render({ + props: { ...passthroughProps, ...propsWeControl }, + slot, + defaultTag: DEFAULT_OPTION_TAG, + name: 'Combobox.Option', + }) +} + +// --- + +Combobox.Input = Input +Combobox.Button = Button +Combobox.Label = Label +Combobox.Options = Options +Combobox.Option = Option diff --git a/packages/@headlessui-react/src/components/description/description.tsx b/packages/@headlessui-react/src/components/description/description.tsx index 716a9b2813..b0dc312e2b 100644 --- a/packages/@headlessui-react/src/components/description/description.tsx +++ b/packages/@headlessui-react/src/components/description/description.tsx @@ -57,10 +57,10 @@ export function useDescriptions(): [ useMemo(() => { return function DescriptionProvider(props: DescriptionProviderProps) { let register = useCallback((value: string) => { - setDescriptionIds(existing => [...existing, value]) + setDescriptionIds((existing) => [...existing, value]) return () => - setDescriptionIds(existing => { + setDescriptionIds((existing) => { let clone = existing.slice() let idx = clone.indexOf(value) if (idx !== -1) clone.splice(idx, 1) diff --git a/packages/@headlessui-react/src/components/dialog/dialog.test.tsx b/packages/@headlessui-react/src/components/dialog/dialog.test.tsx index 4a07169dd0..908023b600 100644 --- a/packages/@headlessui-react/src/components/dialog/dialog.test.tsx +++ b/packages/@headlessui-react/src/components/dialog/dialog.test.tsx @@ -143,7 +143,7 @@ describe('Rendering', () => { Trigger - {data => ( + {(data) => ( <>
{JSON.stringify(data)}
@@ -204,7 +204,7 @@ describe('Rendering', () => { return ( <> - @@ -239,7 +239,7 @@ describe('Rendering', () => { return ( <> - @@ -277,7 +277,7 @@ describe('Rendering', () => { let [isOpen, setIsOpen] = useState(false) return ( <> - @@ -400,7 +400,7 @@ describe('Keyboard interactions', () => { let [isOpen, setIsOpen] = useState(false) return ( <> - @@ -438,7 +438,7 @@ describe('Keyboard interactions', () => { let [isOpen, setIsOpen] = useState(false) return ( <> - @@ -477,14 +477,14 @@ describe('Keyboard interactions', () => { let [isOpen, setIsOpen] = useState(false) return ( <> - Contents { + onKeyDown={(event) => { event.preventDefault() event.stopPropagation() }} @@ -525,7 +525,7 @@ describe('Mouse interactions', () => { let [isOpen, setIsOpen] = useState(false) return ( <> - @@ -559,7 +559,7 @@ describe('Mouse interactions', () => { let [isOpen, setIsOpen] = useState(false) return ( <> - @@ -595,7 +595,7 @@ describe('Mouse interactions', () => { let [isOpen, setIsOpen] = useState(false) return ( <> - + Contents @@ -630,7 +630,7 @@ describe('Mouse interactions', () => { return ( <> - + Contents diff --git a/packages/@headlessui-react/src/components/dialog/dialog.tsx b/packages/@headlessui-react/src/components/dialog/dialog.tsx index aa62837ac1..edf3e3a0fb 100644 --- a/packages/@headlessui-react/src/components/dialog/dialog.tsx +++ b/packages/@headlessui-react/src/components/dialog/dialog.tsx @@ -206,7 +206,7 @@ let DialogRoot = forwardRefWithAs(function Dialog< useInertOthers(internalDialogRef, hasNestedDialogs ? enabled : false) // Handle outside click - useWindowEvent('mousedown', event => { + useWindowEvent('mousedown', (event) => { let target = event.target as HTMLElement if (dialogState !== DialogStates.Open) return @@ -217,7 +217,7 @@ let DialogRoot = forwardRefWithAs(function Dialog< }) // Handle `Escape` to close - useWindowEvent('keydown', event => { + useWindowEvent('keydown', (event) => { if (event.key !== Keys.Escape) return if (dialogState !== DialogStates.Open) return if (hasNestedDialogs) return @@ -250,7 +250,7 @@ let DialogRoot = forwardRefWithAs(function Dialog< if (dialogState !== DialogStates.Open) return if (!internalDialogRef.current) return - let observer = new IntersectionObserver(entries => { + let observer = new IntersectionObserver((entries) => { for (let entry of entries) { if ( entry.boundingClientRect.x === 0 && @@ -277,9 +277,10 @@ let DialogRoot = forwardRefWithAs(function Dialog< [dialogState, state, close, setTitleId] ) - let slot = useMemo(() => ({ open: dialogState === DialogStates.Open }), [ - dialogState, - ]) + let slot = useMemo( + () => ({ open: dialogState === DialogStates.Open }), + [dialogState] + ) let propsWeControl = { ref: dialogRef, @@ -304,11 +305,11 @@ let DialogRoot = forwardRefWithAs(function Dialog< match(message, { [StackMessage.Add]() { containers.current.add(element) - setNestedDialogCount(count => count + 1) + setNestedDialogCount((count) => count + 1) }, [StackMessage.Remove]() { containers.current.add(element) - setNestedDialogCount(count => count - 1) + setNestedDialogCount((count) => count - 1) }, }) }, [])} @@ -348,7 +349,7 @@ type OverlayPropsWeControl = 'id' | 'aria-hidden' | 'onClick' let Overlay = forwardRefWithAs(function Overlay< TTag extends ElementType = typeof DEFAULT_OVERLAY_TAG >(props: Props, ref: Ref) { - let [{ dialogState, close }] = useDialogContext([Dialog.displayName, Overlay.name].join('.')) + let [{ dialogState, close }] = useDialogContext('Dialog.Overlay') let overlayRef = useSyncRefs(ref) let id = `headlessui-dialog-overlay-${useId()}` @@ -364,9 +365,10 @@ let Overlay = forwardRefWithAs(function Overlay< [close] ) - let slot = useMemo(() => ({ open: dialogState === DialogStates.Open }), [ - dialogState, - ]) + let slot = useMemo( + () => ({ open: dialogState === DialogStates.Open }), + [dialogState] + ) let propsWeControl = { ref: overlayRef, id, @@ -394,7 +396,7 @@ type TitlePropsWeControl = 'id' function Title( props: Props ) { - let [{ dialogState, setTitleId }] = useDialogContext([Dialog.displayName, Title.name].join('.')) + let [{ dialogState, setTitleId }] = useDialogContext('Dialog.Title') let id = `headlessui-dialog-title-${useId()}` @@ -403,9 +405,10 @@ function Title( return () => setTitleId(null) }, [id, setTitleId]) - let slot = useMemo(() => ({ open: dialogState === DialogStates.Open }), [ - dialogState, - ]) + let slot = useMemo( + () => ({ open: dialogState === DialogStates.Open }), + [dialogState] + ) let propsWeControl = { id } let passthroughProps = props diff --git a/packages/@headlessui-react/src/components/disclosure/disclosure.test.tsx b/packages/@headlessui-react/src/components/disclosure/disclosure.test.tsx index 6c72cff4e1..1d93d260b5 100644 --- a/packages/@headlessui-react/src/components/disclosure/disclosure.test.tsx +++ b/packages/@headlessui-react/src/components/disclosure/disclosure.test.tsx @@ -20,7 +20,7 @@ jest.mock('../../hooks/use-id') afterAll(() => jest.restoreAllMocks()) function nextFrame() { - return new Promise(resolve => { + return new Promise((resolve) => { requestAnimationFrame(() => { requestAnimationFrame(() => { resolve() diff --git a/packages/@headlessui-react/src/components/disclosure/disclosure.tsx b/packages/@headlessui-react/src/components/disclosure/disclosure.tsx index 587df365f0..5dcd19b609 100644 --- a/packages/@headlessui-react/src/components/disclosure/disclosure.tsx +++ b/packages/@headlessui-react/src/components/disclosure/disclosure.tsx @@ -68,14 +68,14 @@ let reducers: { action: Extract ) => StateDefinition } = { - [ActionTypes.ToggleDisclosure]: state => ({ + [ActionTypes.ToggleDisclosure]: (state) => ({ ...state, disclosureState: match(state.disclosureState, { [DisclosureStates.Open]: DisclosureStates.Closed, [DisclosureStates.Closed]: DisclosureStates.Open, }), }), - [ActionTypes.CloseDisclosure]: state => { + [ActionTypes.CloseDisclosure]: (state) => { if (state.disclosureState === DisclosureStates.Closed) return state return { ...state, disclosureState: DisclosureStates.Closed } }, @@ -227,7 +227,7 @@ let Button = forwardRefWithAs(function Button, ref: Ref ) { - let [state, dispatch] = useDisclosureContext([Disclosure.name, Button.name].join('.')) + let [state, dispatch] = useDisclosureContext('Disclosure.Button') let internalButtonRef = useRef(null) let buttonRef = useSyncRefs(internalButtonRef, ref) @@ -334,8 +334,8 @@ let Panel = forwardRefWithAs(function Panel, ref: Ref ) { - let [state, dispatch] = useDisclosureContext([Disclosure.name, Panel.name].join('.')) - let { close } = useDisclosureAPIContext([Disclosure.name, Panel.name].join('.')) + let [state, dispatch] = useDisclosureContext('Disclosure.Panel') + let { close } = useDisclosureAPIContext('Disclosure.Panel') let panelRef = useSyncRefs(ref, () => { if (state.linkedPanel) return diff --git a/packages/@headlessui-react/src/components/label/label.tsx b/packages/@headlessui-react/src/components/label/label.tsx index 0d23754556..871ef93c6b 100644 --- a/packages/@headlessui-react/src/components/label/label.tsx +++ b/packages/@headlessui-react/src/components/label/label.tsx @@ -52,10 +52,10 @@ export function useLabels(): [string | undefined, (props: LabelProviderProps) => useMemo(() => { return function LabelProvider(props: LabelProviderProps) { let register = useCallback((value: string) => { - setLabelIds(existing => [...existing, value]) + setLabelIds((existing) => [...existing, value]) return () => - setLabelIds(existing => { + setLabelIds((existing) => { let clone = existing.slice() let idx = clone.indexOf(value) if (idx !== -1) clone.splice(idx, 1) diff --git a/packages/@headlessui-react/src/components/listbox/listbox.test.tsx b/packages/@headlessui-react/src/components/listbox/listbox.test.tsx index 90011989f2..eea9fc118c 100644 --- a/packages/@headlessui-react/src/components/listbox/listbox.test.tsx +++ b/packages/@headlessui-react/src/components/listbox/listbox.test.tsx @@ -56,6 +56,7 @@ describe('safeguards', () => { ])( 'should error when we are using a <%s /> without a parent ', suppressConsoleLogs((name, Component) => { + // @ts-expect-error This is fine expect(() => render(createElement(Component))).toThrowError( `<${name} /> is missing a parent component.` ) @@ -396,7 +397,7 @@ describe('Rendering', () => { Trigger - {data => ( + {(data) => ( <> {JSON.stringify(data)} @@ -547,10 +548,10 @@ describe('Rendering composition', () => { Trigger - JSON.stringify(bag)}> + JSON.stringify(bag)}> Option A - JSON.stringify(bag)}> + JSON.stringify(bag)}> Option B @@ -645,7 +646,7 @@ describe('Rendering composition', () => { await click(getListboxButton()) // Verify options are buttons now - getListboxOptions().forEach(option => assertListboxOption(option, { tag: 'button' })) + getListboxOptions().forEach((option) => assertListboxOption(option, { tag: 'button' })) }) ) }) @@ -673,7 +674,7 @@ describe('Composition', () => { - {data => ( + {(data) => ( <> {JSON.stringify(data)} @@ -756,7 +757,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option, { selected: false })) + options.forEach((option) => assertListboxOption(option, { selected: false })) // Verify that the first listbox option is active assertActiveListboxOption(options[0]) @@ -918,7 +919,7 @@ describe('Keyboard interactions', () => { Trigger - {myOptions.map(myOption => ( + {myOptions.map((myOption) => ( {myOption.name} @@ -1139,7 +1140,7 @@ describe('Keyboard interactions', () => { return ( { + onChange={(value) => { setValue(value) handleChange(value) }} @@ -1234,7 +1235,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[0]) }) ) @@ -1462,7 +1463,7 @@ describe('Keyboard interactions', () => { return ( { + onChange={(value) => { setValue(value) handleChange(value) }} @@ -1600,7 +1601,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[0]) // Try to tab @@ -1651,7 +1652,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[0]) // Try to Shift+Tab @@ -1704,7 +1705,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) // Verify that the first listbox option is active assertActiveListboxOption(options[0]) @@ -1844,7 +1845,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[0]) // We should be able to go down once @@ -1892,7 +1893,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[1]) // We should be able to go down once @@ -1934,7 +1935,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[2]) }) ) @@ -1970,7 +1971,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[0]) // We should be able to go right once @@ -2027,7 +2028,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) // ! ALERT: The LAST option should now be active assertActiveListboxOption(options[2]) @@ -2171,7 +2172,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[0]) }) ) @@ -2209,7 +2210,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[2]) // We should not be able to go up (because those are disabled) @@ -2260,7 +2261,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[2]) // We should be able to go down once @@ -2318,7 +2319,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[2]) // We should be able to go left once @@ -3198,7 +3199,7 @@ describe('Mouse interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) }) ) @@ -3726,7 +3727,7 @@ describe('Mouse interactions', () => { return ( { + onChange={(value) => { setValue(value) handleChange(value) }} @@ -3777,7 +3778,7 @@ describe('Mouse interactions', () => { return ( { + onChange={(value) => { setValue(value) handleChange(value) }} diff --git a/packages/@headlessui-react/src/components/listbox/listbox.tsx b/packages/@headlessui-react/src/components/listbox/listbox.tsx index 26432b85b4..da2741cef6 100644 --- a/packages/@headlessui-react/src/components/listbox/listbox.tsx +++ b/packages/@headlessui-react/src/components/listbox/listbox.tsx @@ -119,8 +119,8 @@ let reducers: { let activeOptionIndex = calculateActiveIndex(action, { resolveItems: () => state.options, resolveActiveIndex: () => state.activeOptionIndex, - resolveId: item => item.id, - resolveDisabled: item => item.dataRef.current.disabled, + resolveId: (item) => item.id, + resolveDisabled: (item) => item.dataRef.current.disabled, }) if (state.searchQuery === '' && state.activeOptionIndex === activeOptionIndex) return state @@ -140,7 +140,7 @@ let reducers: { : state.options let matchingOption = reOrderedOptions.find( - option => + (option) => !option.dataRef.current.disabled && option.dataRef.current.textValue?.startsWith(searchQuery) ) @@ -175,7 +175,7 @@ let reducers: { let currentActiveOption = state.activeOptionIndex !== null ? nextOptions[state.activeOptionIndex] : null - let idx = nextOptions.findIndex(a => a.id === action.id) + let idx = nextOptions.findIndex((a) => a.id === action.id) if (idx !== -1) nextOptions.splice(idx, 1) @@ -251,12 +251,13 @@ export function Listbox dispatch({ type: ActionTypes.SetDisabled, disabled }), [disabled]) - useIsoMorphicEffect(() => dispatch({ type: ActionTypes.SetOrientation, orientation }), [ - orientation, - ]) + useIsoMorphicEffect( + () => dispatch({ type: ActionTypes.SetOrientation, orientation }), + [orientation] + ) // Handle outside click - useWindowEvent('mousedown', event => { + useWindowEvent('mousedown', (event) => { let target = event.target as HTMLElement if (listboxState !== ListboxStates.Open) return @@ -318,7 +319,7 @@ let Button = forwardRefWithAs(function Button, ref: Ref ) { - let [state, dispatch] = useListboxContext([Listbox.name, Button.name].join('.')) + let [state, dispatch] = useListboxContext('Listbox.Button') let buttonRef = useSyncRefs(state.buttonRef, ref) let id = `headlessui-listbox-button-${useId()}` @@ -422,12 +423,13 @@ type LabelPropsWeControl = 'id' | 'ref' | 'onClick' function Label( props: Props ) { - let [state] = useListboxContext([Listbox.name, Label.name].join('.')) + let [state] = useListboxContext('Listbox.Label') let id = `headlessui-listbox-label-${useId()}` - let handleClick = useCallback(() => state.buttonRef.current?.focus({ preventScroll: true }), [ - state.buttonRef, - ]) + let handleClick = useCallback( + () => state.buttonRef.current?.focus({ preventScroll: true }), + [state.buttonRef] + ) let slot = useMemo( () => ({ open: state.listboxState === ListboxStates.Open, disabled: state.disabled }), @@ -466,7 +468,7 @@ let Options = forwardRefWithAs(function Options< PropsForFeatures, ref: Ref ) { - let [state, dispatch] = useListboxContext([Listbox.name, Options.name].join('.')) + let [state, dispatch] = useListboxContext('Listbox.Options') let optionsRef = useSyncRefs(state.optionsRef, ref) let id = `headlessui-listbox-options-${useId()}` @@ -561,10 +563,10 @@ let Options = forwardRefWithAs(function Options< [d, dispatch, searchDisposables, state] ) - let labelledby = useComputed(() => state.labelRef.current?.id ?? state.buttonRef.current?.id, [ - state.labelRef.current, - state.buttonRef.current, - ]) + let labelledby = useComputed( + () => state.labelRef.current?.id ?? state.buttonRef.current?.id, + [state.labelRef.current, state.buttonRef.current] + ) let slot = useMemo( () => ({ open: state.listboxState === ListboxStates.Open }), @@ -625,7 +627,7 @@ function Option< } ) { let { disabled = false, value, ...passthroughProps } = props - let [state, dispatch] = useListboxContext([Listbox.name, Option.name].join('.')) + let [state, dispatch] = useListboxContext('Listbox.Option') let id = `headlessui-listbox-option-${useId()}` let active = state.activeOptionIndex !== null ? state.options[state.activeOptionIndex].id === id : false @@ -692,11 +694,10 @@ function Option< dispatch({ type: ActionTypes.GoToOption, focus: Focus.Nothing }) }, [disabled, active, dispatch]) - let slot = useMemo(() => ({ active, selected, disabled }), [ - active, - selected, - disabled, - ]) + let slot = useMemo( + () => ({ active, selected, disabled }), + [active, selected, disabled] + ) let propsWeControl = { id, role: 'option', diff --git a/packages/@headlessui-react/src/components/menu/menu.test.tsx b/packages/@headlessui-react/src/components/menu/menu.test.tsx index a5a2a9b67c..1fc853d9b6 100644 --- a/packages/@headlessui-react/src/components/menu/menu.test.tsx +++ b/packages/@headlessui-react/src/components/menu/menu.test.tsx @@ -253,7 +253,7 @@ describe('Rendering', () => { Trigger - {data => ( + {(data) => ( <> {JSON.stringify(data)} @@ -403,10 +403,10 @@ describe('Rendering composition', () => { Trigger - JSON.stringify(bag)}> + JSON.stringify(bag)}> Item A - JSON.stringify(bag)}> + JSON.stringify(bag)}> Item B @@ -484,7 +484,7 @@ describe('Rendering composition', () => { // Verify items are buttons now let items = getMenuItems() - items.forEach(item => assertMenuItem(item, { tag: 'button' })) + items.forEach((item) => assertMenuItem(item, { tag: 'button' })) }) ) @@ -496,11 +496,11 @@ describe('Rendering composition', () => { Trigger
-
+
Item A Item B
-
+
Item C
@@ -508,7 +508,7 @@ describe('Rendering composition', () => {
-
+
Item E
@@ -523,11 +523,11 @@ describe('Rendering composition', () => { expect.hasAssertions() - document.querySelectorAll('.outer').forEach(element => { + document.querySelectorAll('.outer').forEach((element) => { expect(element).not.toHaveAttribute('role', 'none') }) - document.querySelectorAll('.inner').forEach(element => { + document.querySelectorAll('.inner').forEach((element) => { expect(element).toHaveAttribute('role', 'none') }) }) @@ -557,7 +557,7 @@ describe('Composition', () => { - {data => ( + {(data) => ( <> {JSON.stringify(data)} @@ -611,7 +611,7 @@ describe('Composition', () => { - {data => ( + {(data) => ( <> {JSON.stringify(data)} @@ -693,7 +693,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) // Verify that the first menu item is active assertMenuLinkedWithMenuItem(items[0]) @@ -1057,7 +1057,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) assertMenuLinkedWithMenuItem(items[0]) }) ) @@ -1395,7 +1395,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) assertMenuLinkedWithMenuItem(items[0]) // Try to tab @@ -1444,7 +1444,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) assertMenuLinkedWithMenuItem(items[0]) // Try to Shift+Tab @@ -1495,7 +1495,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) // Verify that the first menu item is active assertMenuLinkedWithMenuItem(items[0]) @@ -1589,7 +1589,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) assertMenuLinkedWithMenuItem(items[0]) // We should be able to go down once @@ -1637,7 +1637,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) assertMenuLinkedWithMenuItem(items[1]) // We should be able to go down once @@ -1679,7 +1679,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) assertMenuLinkedWithMenuItem(items[2]) }) ) @@ -1723,7 +1723,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) // ! ALERT: The LAST item should now be active assertMenuLinkedWithMenuItem(items[2]) @@ -1821,7 +1821,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) assertMenuLinkedWithMenuItem(items[0]) }) ) @@ -1859,7 +1859,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) assertMenuLinkedWithMenuItem(items[2]) // We should not be able to go up (because those are disabled) @@ -1909,7 +1909,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) assertMenuLinkedWithMenuItem(items[2]) // We should be able to go down once @@ -2736,7 +2736,7 @@ describe('Mouse interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) }) ) diff --git a/packages/@headlessui-react/src/components/menu/menu.tsx b/packages/@headlessui-react/src/components/menu/menu.tsx index 3e871fe15a..962549fdf6 100644 --- a/packages/@headlessui-react/src/components/menu/menu.tsx +++ b/packages/@headlessui-react/src/components/menu/menu.tsx @@ -91,8 +91,8 @@ let reducers: { let activeItemIndex = calculateActiveIndex(action, { resolveItems: () => state.items, resolveActiveIndex: () => state.activeItemIndex, - resolveId: item => item.id, - resolveDisabled: item => item.dataRef.current.disabled, + resolveId: (item) => item.id, + resolveDisabled: (item) => item.dataRef.current.disabled, }) if (state.searchQuery === '' && state.activeItemIndex === activeItemIndex) return state @@ -109,7 +109,7 @@ let reducers: { : state.items let matchingItem = reOrderedItems.find( - item => + (item) => item.dataRef.current.textValue?.startsWith(searchQuery) && !item.dataRef.current.disabled ) @@ -139,7 +139,7 @@ let reducers: { let nextItems = state.items.slice() let currentActiveItem = state.activeItemIndex !== null ? nextItems[state.activeItemIndex] : null - let idx = nextItems.findIndex(a => a.id === action.id) + let idx = nextItems.findIndex((a) => a.id === action.id) if (idx !== -1) nextItems.splice(idx, 1) @@ -196,7 +196,7 @@ export function Menu( let [{ menuState, itemsRef, buttonRef }, dispatch] = reducerBag // Handle outside click - useWindowEvent('mousedown', event => { + useWindowEvent('mousedown', (event) => { let target = event.target as HTMLElement if (menuState !== MenuStates.Open) return @@ -212,9 +212,10 @@ export function Menu( } }) - let slot = useMemo(() => ({ open: menuState === MenuStates.Open }), [ - menuState, - ]) + let slot = useMemo( + () => ({ open: menuState === MenuStates.Open }), + [menuState] + ) return ( @@ -249,7 +250,7 @@ let Button = forwardRefWithAs(function Button, ref: Ref ) { - let [state, dispatch] = useMenuContext([Menu.name, Button.name].join('.')) + let [state, dispatch] = useMenuContext('Menu.Button') let buttonRef = useSyncRefs(state.buttonRef, ref) let id = `headlessui-menu-button-${useId()}` @@ -307,9 +308,10 @@ let Button = forwardRefWithAs(function Button(() => ({ open: state.menuState === MenuStates.Open }), [ - state, - ]) + let slot = useMemo( + () => ({ open: state.menuState === MenuStates.Open }), + [state] + ) let passthroughProps = props let propsWeControl = { ref: buttonRef, @@ -352,7 +354,7 @@ let Items = forwardRefWithAs(function Items, ref: Ref ) { - let [state, dispatch] = useMenuContext([Menu.name, Items.name].join('.')) + let [state, dispatch] = useMenuContext('Menu.Items') let itemsRef = useSyncRefs(state.itemsRef, ref) let id = `headlessui-menu-items-${useId()}` @@ -471,9 +473,10 @@ let Items = forwardRefWithAs(function Items(() => ({ open: state.menuState === MenuStates.Open }), [ - state, - ]) + let slot = useMemo( + () => ({ open: state.menuState === MenuStates.Open }), + [state] + ) let propsWeControl = { 'aria-activedescendant': state.activeItemIndex === null ? undefined : state.items[state.activeItemIndex]?.id, @@ -522,7 +525,7 @@ function Item( } ) { let { disabled = false, onClick, ...passthroughProps } = props - let [state, dispatch] = useMenuContext([Menu.name, Item.name].join('.')) + let [state, dispatch] = useMenuContext('Menu.Item') let id = `headlessui-menu-item-${useId()}` let active = state.activeItemIndex !== null ? state.items[state.activeItemIndex].id === id : false diff --git a/packages/@headlessui-react/src/components/popover/popover.test.tsx b/packages/@headlessui-react/src/components/popover/popover.test.tsx index c39fc8a43a..f8f73a2d00 100644 --- a/packages/@headlessui-react/src/components/popover/popover.test.tsx +++ b/packages/@headlessui-react/src/components/popover/popover.test.tsx @@ -23,7 +23,7 @@ jest.mock('../../hooks/use-id') afterAll(() => jest.restoreAllMocks()) function nextFrame() { - return new Promise(resolve => { + return new Promise((resolve) => { requestAnimationFrame(() => { requestAnimationFrame(() => { resolve() diff --git a/packages/@headlessui-react/src/components/popover/popover.tsx b/packages/@headlessui-react/src/components/popover/popover.tsx index f0e7264543..779a122917 100644 --- a/packages/@headlessui-react/src/components/popover/popover.tsx +++ b/packages/@headlessui-react/src/components/popover/popover.tsx @@ -75,7 +75,7 @@ let reducers: { action: Extract ) => StateDefinition } = { - [ActionTypes.TogglePopover]: state => ({ + [ActionTypes.TogglePopover]: (state) => ({ ...state, popoverState: match(state.popoverState, { [PopoverStates.Open]: PopoverStates.Closed, @@ -217,7 +217,7 @@ export function Popover( ) // Handle outside click - useWindowEvent('mousedown', event => { + useWindowEvent('mousedown', (event) => { let target = event.target as HTMLElement if (popoverState !== PopoverStates.Open) return @@ -296,7 +296,7 @@ let Button = forwardRefWithAs(function Button, ref: Ref ) { - let [state, dispatch] = usePopoverContext([Popover.name, Button.name].join('.')) + let [state, dispatch] = usePopoverContext('Popover.Button') let internalButtonRef = useRef(null) let groupContext = usePopoverGroupContext() @@ -308,7 +308,7 @@ let Button = forwardRefWithAs(function Button dispatch({ type: ActionTypes.SetButton, button }) + isWithinPanel ? null : (button) => dispatch({ type: ActionTypes.SetButton, button }) ) let withinPanelButtonRef = useSyncRefs(internalButtonRef, ref) @@ -517,7 +517,7 @@ let Overlay = forwardRefWithAs(function Overlay< PropsForFeatures, ref: Ref ) { - let [{ popoverState }, dispatch] = usePopoverContext([Popover.name, Overlay.name].join('.')) + let [{ popoverState }, dispatch] = usePopoverContext('Popover.Overlay') let overlayRef = useSyncRefs(ref) let id = `headlessui-popover-overlay-${useId()}` @@ -539,9 +539,10 @@ let Overlay = forwardRefWithAs(function Overlay< [dispatch] ) - let slot = useMemo(() => ({ open: popoverState === PopoverStates.Open }), [ - popoverState, - ]) + let slot = useMemo( + () => ({ open: popoverState === PopoverStates.Open }), + [popoverState] + ) let propsWeControl = { ref: overlayRef, id, @@ -580,11 +581,11 @@ let Panel = forwardRefWithAs(function Panel(null) - let panelRef = useSyncRefs(internalPanelRef, ref, panel => { + let panelRef = useSyncRefs(internalPanelRef, ref, (panel) => { dispatch({ type: ActionTypes.SetPanel, panel }) }) @@ -639,7 +640,7 @@ let Panel = forwardRefWithAs(function Panel { + useWindowEvent('keydown', (event) => { if (state.popoverState !== PopoverStates.Open) return if (!internalPanelRef.current) return if (event.key !== Keys.Tab) return @@ -665,7 +666,7 @@ let Panel = forwardRefWithAs(function Panel !internalPanelRef.current?.contains(element)) // Ignore items in panel + .filter((element) => !internalPanelRef.current?.contains(element)) // Ignore items in panel // Try to focus the next element, however it could fail if we are in a // Portal that happens to be the very last one in the DOM. In that @@ -730,7 +731,7 @@ function Group( let unregisterPopover = useCallback( (registerbag: PopoverRegisterBag) => { - setPopovers(existing => { + setPopovers((existing) => { let idx = existing.indexOf(registerbag) if (idx !== -1) { let clone = existing.slice() @@ -745,7 +746,7 @@ function Group( let registerPopover = useCallback( (registerbag: PopoverRegisterBag) => { - setPopovers(existing => [...existing, registerbag]) + setPopovers((existing) => [...existing, registerbag]) return () => unregisterPopover(registerbag) }, [setPopovers, unregisterPopover] @@ -757,7 +758,7 @@ function Group( if (groupRef.current?.contains(element)) return true // Check if the focus is in one of the button or panel elements. This is important in case you are rendering inside a Portal. - return popovers.some(bag => { + return popovers.some((bag) => { return ( document.getElementById(bag.buttonId)?.contains(element) || document.getElementById(bag.panelId)?.contains(element) diff --git a/packages/@headlessui-react/src/components/portal/portal.test.tsx b/packages/@headlessui-react/src/components/portal/portal.test.tsx index eea7c4cb06..6b21ea7a5c 100644 --- a/packages/@headlessui-react/src/components/portal/portal.test.tsx +++ b/packages/@headlessui-react/src/components/portal/portal.test.tsx @@ -82,10 +82,10 @@ it('should cleanup the Portal root when the last Portal is unmounted', async () return (
- - @@ -151,21 +151,21 @@ it('should be possible to render multiple portals at the same time', async () => return (
- - - - diff --git a/packages/@headlessui-react/src/components/radio-group/radio-group.test.tsx b/packages/@headlessui-react/src/components/radio-group/radio-group.test.tsx index f9f7076c70..010602e64f 100644 --- a/packages/@headlessui-react/src/components/radio-group/radio-group.test.tsx +++ b/packages/@headlessui-react/src/components/radio-group/radio-group.test.tsx @@ -113,7 +113,7 @@ describe('Rendering', () => { return ( <> - + Pizza Delivery {showFirst && Pickup} @@ -145,7 +145,7 @@ describe('Rendering', () => { let [disabled, setDisabled] = useState(true) return ( <> - + Pizza Delivery Pickup @@ -208,7 +208,7 @@ describe('Rendering', () => { let [disabled, setDisabled] = useState(true) return ( <> - + Pizza Delivery Pickup @@ -745,7 +745,7 @@ describe('Keyboard interactions', () => { { + onChange={(v) => { setValue(v) changeFn(v) }} @@ -815,7 +815,7 @@ describe('Mouse interactions', () => { { + onChange={(v) => { setValue(v) changeFn(v) }} diff --git a/packages/@headlessui-react/src/components/radio-group/radio-group.tsx b/packages/@headlessui-react/src/components/radio-group/radio-group.tsx index b65bb64a8a..3c81a9e9a2 100644 --- a/packages/@headlessui-react/src/components/radio-group/radio-group.tsx +++ b/packages/@headlessui-react/src/components/radio-group/radio-group.tsx @@ -61,7 +61,7 @@ let reducers: { }, [ActionTypes.UnregisterOption](state, action) { let options = state.options.slice() - let idx = state.options.findIndex(radio => radio.id === action.id) + let idx = state.options.findIndex((radio) => radio.id === action.id) if (idx === -1) return state options.splice(idx, 1) return { ...state, options } @@ -123,23 +123,23 @@ export function RadioGroup< let firstOption = useMemo( () => - options.find(option => { + options.find((option) => { if (option.propsRef.current.disabled) return false return true }), [options] ) let containsCheckedOption = useMemo( - () => options.some(option => option.propsRef.current.value === value), + () => options.some((option) => option.propsRef.current.value === value), [options, value] ) let triggerChange = useCallback( - nextValue => { + (nextValue) => { if (disabled) return false if (nextValue === value) return false - let nextOption = options.find(option => option.propsRef.current.value === nextValue)?.propsRef - .current + let nextOption = options.find((option) => option.propsRef.current.value === nextValue) + ?.propsRef.current if (nextOption?.disabled) return false onChange(nextValue) @@ -166,8 +166,8 @@ export function RadioGroup< if (!container) return let all = options - .filter(option => option.propsRef.current.disabled === false) - .map(radio => radio.element.current) as HTMLElement[] + .filter((option) => option.propsRef.current.disabled === false) + .map((radio) => radio.element.current) as HTMLElement[] switch (event.key) { case Keys.ArrowLeft: @@ -180,7 +180,7 @@ export function RadioGroup< if (result === FocusResult.Success) { let activeOption = options.find( - option => option.element.current === document.activeElement + (option) => option.element.current === document.activeElement ) if (activeOption) triggerChange(activeOption.propsRef.current.value) } @@ -197,7 +197,7 @@ export function RadioGroup< if (result === FocusResult.Success) { let activeOption = options.find( - option => option.element.current === document.activeElement + (option) => option.element.current === document.activeElement ) if (activeOption) triggerChange(activeOption.propsRef.current.value) } @@ -210,7 +210,7 @@ export function RadioGroup< event.stopPropagation() let activeOption = options.find( - option => option.element.current === document.activeElement + (option) => option.element.current === document.activeElement ) if (activeOption) triggerChange(activeOption.propsRef.current.value) } @@ -322,14 +322,12 @@ function Option< firstOption, containsCheckedOption, value: radioGroupValue, - } = useRadioGroupContext([RadioGroup.name, Option.name].join('.')) + } = useRadioGroupContext('RadioGroup.Option') - useIsoMorphicEffect(() => registerOption({ id, element: optionRef, propsRef }), [ - id, - registerOption, - optionRef, - props, - ]) + useIsoMorphicEffect( + () => registerOption({ id, element: optionRef, propsRef }), + [id, registerOption, optionRef, props] + ) let handleClick = useCallback(() => { if (!change(value)) return diff --git a/packages/@headlessui-react/src/components/switch/switch.test.tsx b/packages/@headlessui-react/src/components/switch/switch.test.tsx index d566a48261..986664b79d 100644 --- a/packages/@headlessui-react/src/components/switch/switch.test.tsx +++ b/packages/@headlessui-react/src/components/switch/switch.test.tsx @@ -214,7 +214,7 @@ describe('Keyboard interactions', () => { return ( { + onChange={(value) => { setState(value) handleChange(value) }} @@ -297,7 +297,7 @@ describe('Mouse interactions', () => { return ( { + onChange={(value) => { setState(value) handleChange(value) }} @@ -331,7 +331,7 @@ describe('Mouse interactions', () => { { + onChange={(value) => { setState(value) handleChange(value) }} @@ -373,7 +373,7 @@ describe('Mouse interactions', () => { { + onChange={(value) => { setState(value) handleChange(value) }} diff --git a/packages/@headlessui-react/src/components/tabs/tabs.test.tsx b/packages/@headlessui-react/src/components/tabs/tabs.test.tsx index b58f138035..d824817405 100644 --- a/packages/@headlessui-react/src/components/tabs/tabs.test.tsx +++ b/packages/@headlessui-react/src/components/tabs/tabs.test.tsx @@ -81,7 +81,7 @@ describe('Rendering', () => { return ( <> - + Tab 1 @@ -118,7 +118,7 @@ describe('Rendering', () => { it('should expose the `selectedIndex` on the `Tab.Group` component', async () => { render( - {data => ( + {(data) => ( <>
{JSON.stringify(data)}
@@ -153,7 +153,7 @@ describe('Rendering', () => { render( - {data => ( + {(data) => ( <>
{JSON.stringify(data)}
Tab 1 @@ -192,7 +192,7 @@ describe('Rendering', () => {
- {data => ( + {(data) => ( <>
{JSON.stringify(data)}
Content 1 @@ -220,7 +220,7 @@ describe('Rendering', () => { - {data => ( + {(data) => ( <>
{JSON.stringify(data)}
Tab 1 @@ -228,7 +228,7 @@ describe('Rendering', () => { )}
- {data => ( + {(data) => ( <>
{JSON.stringify(data)}
Tab 2 @@ -236,7 +236,7 @@ describe('Rendering', () => { )}
- {data => ( + {(data) => ( <>
{JSON.stringify(data)}
Tab 3 @@ -287,7 +287,7 @@ describe('Rendering', () => { - {data => ( + {(data) => ( <>
{JSON.stringify(data)}
Content 1 @@ -295,7 +295,7 @@ describe('Rendering', () => { )}
- {data => ( + {(data) => ( <>
{JSON.stringify(data)}
Content 2 @@ -303,7 +303,7 @@ describe('Rendering', () => { )}
- {data => ( + {(data) => ( <>
{JSON.stringify(data)}
Content 3 @@ -514,7 +514,7 @@ describe('Rendering', () => { <> { + onChange={(value) => { setSelectedIndex(value) handleChange(value) }} @@ -533,7 +533,7 @@ describe('Rendering', () => { - + ) } diff --git a/packages/@headlessui-react/src/components/tabs/tabs.tsx b/packages/@headlessui-react/src/components/tabs/tabs.tsx index 5e057e55d5..4f8c000ecd 100644 --- a/packages/@headlessui-react/src/components/tabs/tabs.tsx +++ b/packages/@headlessui-react/src/components/tabs/tabs.tsx @@ -83,14 +83,14 @@ let reducers: { return { ...state, tabs: [...state.tabs, action.tab] } }, [ActionTypes.UnregisterTab](state, action) { - return { ...state, tabs: state.tabs.filter(tab => tab !== action.tab) } + return { ...state, tabs: state.tabs.filter((tab) => tab !== action.tab) } }, [ActionTypes.RegisterPanel](state, action) { if (state.panels.includes(action.panel)) return state return { ...state, panels: [...state.panels, action.panel] } }, [ActionTypes.UnregisterPanel](state, action) { - return { ...state, panels: state.panels.filter(panel => panel !== action.panel) } + return { ...state, panels: state.panels.filter((panel) => panel !== action.panel) } }, [ActionTypes.ForceRerender](state) { return { ...state } @@ -171,8 +171,8 @@ function Tabs( if (state.tabs.length <= 0) return if (selectedIndex === null && state.selectedIndex !== null) return - let tabs = state.tabs.map(tab => tab.current).filter(Boolean) as HTMLElement[] - let focusableTabs = tabs.filter(tab => !tab.hasAttribute('disabled')) + let tabs = state.tabs.map((tab) => tab.current).filter(Boolean) as HTMLElement[] + let focusableTabs = tabs.filter((tab) => !tab.hasAttribute('disabled')) let indexToSet = selectedIndex ?? defaultIndex @@ -194,7 +194,7 @@ function Tabs( let before = tabs.slice(0, indexToSet) let after = tabs.slice(indexToSet) - let next = [...after, ...before].find(tab => focusableTabs.includes(tab)) + let next = [...after, ...before].find((tab) => focusableTabs.includes(tab)) if (!next) return dispatch({ type: ActionTypes.SetSelectedIndex, index: tabs.indexOf(next) }) @@ -245,7 +245,7 @@ type ListPropsWeControl = 'role' | 'aria-orientation' function List( props: Props & {} ) { - let [{ selectedIndex, orientation }] = useTabsContext([Tab.name, List.name].join('.')) + let [{ selectedIndex, orientation }] = useTabsContext('Tab.List') let slot = { selectedIndex } let propsWeControl = { @@ -275,13 +275,11 @@ export function Tab( ) { let id = `headlessui-tabs-tab-${useId()}` - let [ - { selectedIndex, tabs, panels, orientation, activation }, - { dispatch, change }, - ] = useTabsContext(Tab.name) + let [{ selectedIndex, tabs, panels, orientation, activation }, { dispatch, change }] = + useTabsContext(Tab.name) let internalTabRef = useRef(null) - let tabRef = useSyncRefs(internalTabRef, element => { + let tabRef = useSyncRefs(internalTabRef, (element) => { if (!element) return dispatch({ type: ActionTypes.ForceRerender }) }) @@ -296,7 +294,7 @@ export function Tab( let handleKeyDown = useCallback( (event: ReactKeyboardEvent) => { - let list = tabs.map(tab => tab.current).filter(Boolean) as HTMLElement[] + let list = tabs.map((tab) => tab.current).filter(Boolean) as HTMLElement[] if (event.key === Keys.Space || event.key === Keys.Enter) { event.preventDefault() @@ -380,7 +378,7 @@ interface PanelsRenderPropArg { function Panels( props: Props ) { - let [{ selectedIndex }] = useTabsContext([Tab.name, Panels.name].join('.')) + let [{ selectedIndex }] = useTabsContext('Tab.Panels') let slot = useMemo(() => ({ selectedIndex }), [selectedIndex]) @@ -405,13 +403,11 @@ function Panel( props: Props & PropsForFeatures ) { - let [{ selectedIndex, tabs, panels }, { dispatch }] = useTabsContext( - [Tab.name, Panel.name].join('.') - ) + let [{ selectedIndex, tabs, panels }, { dispatch }] = useTabsContext('Tab.Panel') let id = `headlessui-tabs-panel-${useId()}` let internalPanelRef = useRef(null) - let panelRef = useSyncRefs(internalPanelRef, element => { + let panelRef = useSyncRefs(internalPanelRef, (element) => { if (!element) return dispatch({ type: ActionTypes.ForceRerender }) }) diff --git a/packages/@headlessui-react/src/components/transitions/transition.test.tsx b/packages/@headlessui-react/src/components/transitions/transition.test.tsx index 3a3aeb0f0c..8dfcc004c4 100644 --- a/packages/@headlessui-react/src/components/transitions/transition.test.tsx +++ b/packages/@headlessui-react/src/components/transitions/transition.test.tsx @@ -26,8 +26,6 @@ it( expect(() => { render( - // @ts-expect-error Disabling TS because it does require us to use a show prop. But non - // TypeScript projects won't benefit from this.
Children
@@ -445,7 +443,7 @@ describe('Transitions', () => { Hello! - @@ -488,14 +486,15 @@ describe('Transitions', () => { return ( <> - + Hello! - @@ -538,14 +537,15 @@ describe('Transitions', () => { return ( <> - + Hello! - @@ -591,7 +591,7 @@ describe('Transitions', () => { Hello! - @@ -642,7 +642,7 @@ describe('Transitions', () => { Hello! - @@ -696,7 +696,7 @@ describe('Transitions', () => { Hello! - @@ -757,7 +757,7 @@ describe('Transitions', () => { Hello! - @@ -843,7 +843,7 @@ describe('Transitions', () => { Hello! - @@ -943,7 +943,7 @@ describe('Transitions', () => { - @@ -1027,7 +1027,7 @@ describe('Transitions', () => { - @@ -1138,7 +1138,7 @@ describe('Events', () => { Hello! - diff --git a/packages/@headlessui-react/src/components/transitions/transition.tsx b/packages/@headlessui-react/src/components/transitions/transition.tsx index c3446f3caf..f3f8595273 100644 --- a/packages/@headlessui-react/src/components/transitions/transition.tsx +++ b/packages/@headlessui-react/src/components/transitions/transition.tsx @@ -28,9 +28,10 @@ import { useServerHandoffComplete } from '../../hooks/use-server-handoff-complet type ID = ReturnType function useSplitClasses(classes: string = '') { - return useMemo(() => classes.split(' ').filter(className => className.trim().length > 1), [ - classes, - ]) + return useMemo( + () => classes.split(' ').filter((className) => className.trim().length > 1), + [classes] + ) } interface TransitionContextValues { @@ -287,23 +288,37 @@ function TransitionChild { - isTransitioning.current = false - if (reason === Reason.Finished) events.current.afterEnter() - }) - : transition(node, leaveClasses, leaveFromClasses, leaveToClasses, enteredClasses, reason => { - isTransitioning.current = false - - if (reason !== Reason.Finished) return - - // When we don't have children anymore we can safely unregister from the parent and hide - // ourselves. - if (!hasChildren(nesting)) { - setState(TreeStates.Hidden) - unregister(id) - events.current.afterLeave() + ? transition( + node, + enterClasses, + enterFromClasses, + enterToClasses, + enteredClasses, + (reason) => { + isTransitioning.current = false + if (reason === Reason.Finished) events.current.afterEnter() + } + ) + : transition( + node, + leaveClasses, + leaveFromClasses, + leaveToClasses, + enteredClasses, + (reason) => { + isTransitioning.current = false + + if (reason !== Reason.Finished) return + + // When we don't have children anymore we can safely unregister from the parent and hide + // ourselves. + if (!hasChildren(nesting)) { + setState(TreeStates.Hidden) + unregister(id) + events.current.afterLeave() + } } - }) + ) }, [ events, id, @@ -359,7 +374,7 @@ export function Transition is used but it is missing a `show={true | false}` prop.') } diff --git a/packages/@headlessui-react/src/components/transitions/utils/transition.test.ts b/packages/@headlessui-react/src/components/transitions/utils/transition.test.ts index 9918716179..58cd91a0aa 100644 --- a/packages/@headlessui-react/src/components/transitions/utils/transition.test.ts +++ b/packages/@headlessui-react/src/components/transitions/utils/transition.test.ts @@ -17,7 +17,7 @@ it('should be possible to transition', async () => { d.add( reportChanges( () => document.body.innerHTML, - content => { + (content) => { snapshots.push({ content, recordedAt: process.hrtime.bigint(), @@ -26,11 +26,11 @@ it('should be possible to transition', async () => { ) ) - await new Promise(resolve => { + await new Promise((resolve) => { transition(element, ['enter'], ['enterFrom'], ['enterTo'], ['entered'], resolve) }) - await new Promise(resolve => d.nextFrame(resolve)) + await new Promise((resolve) => d.nextFrame(resolve)) // Initial render: expect(snapshots[0].content).toEqual('
') @@ -61,7 +61,7 @@ it('should wait the correct amount of time to finish a transition', async () => d.add( reportChanges( () => document.body.innerHTML, - content => { + (content) => { snapshots.push({ content, recordedAt: process.hrtime.bigint(), @@ -70,11 +70,11 @@ it('should wait the correct amount of time to finish a transition', async () => ) ) - let reason = await new Promise(resolve => { + let reason = await new Promise((resolve) => { transition(element, ['enter'], ['enterFrom'], ['enterTo'], ['entered'], resolve) }) - await new Promise(resolve => d.nextFrame(resolve)) + await new Promise((resolve) => d.nextFrame(resolve)) expect(reason).toBe(Reason.Finished) // Initial render: @@ -118,7 +118,7 @@ it('should keep the delay time into account', async () => { d.add( reportChanges( () => document.body.innerHTML, - content => { + (content) => { snapshots.push({ content, recordedAt: process.hrtime.bigint(), @@ -127,11 +127,11 @@ it('should keep the delay time into account', async () => { ) ) - let reason = await new Promise(resolve => { + let reason = await new Promise((resolve) => { transition(element, ['enter'], ['enterFrom'], ['enterTo'], ['entered'], resolve) }) - await new Promise(resolve => d.nextFrame(resolve)) + await new Promise((resolve) => d.nextFrame(resolve)) expect(reason).toBe(Reason.Finished) let estimatedDuration = Number( @@ -161,7 +161,7 @@ it('should be possible to cancel a transition at any time', async () => { d.add( reportChanges( () => document.body.innerHTML, - content => { + (content) => { let recordedAt = process.hrtime.bigint() let total = snapshots.length @@ -178,16 +178,16 @@ it('should be possible to cancel a transition at any time', async () => { expect.assertions(2) // Setup the transition - let cancel = transition(element, ['enter'], ['enterFrom'], ['enterTo'], ['entered'], reason => { + let cancel = transition(element, ['enter'], ['enterFrom'], ['enterTo'], ['entered'], (reason) => { expect(reason).toBe(Reason.Cancelled) }) // Wait for a bit - await new Promise(resolve => setTimeout(resolve, 20)) + await new Promise((resolve) => setTimeout(resolve, 20)) // Cancel the transition cancel() - await new Promise(resolve => d.nextFrame(resolve)) + await new Promise((resolve) => d.nextFrame(resolve)) - expect(snapshots.map(snapshot => snapshot.content).join('\n')).not.toContain('enterTo') + expect(snapshots.map((snapshot) => snapshot.content).join('\n')).not.toContain('enterTo') }) diff --git a/packages/@headlessui-react/src/components/transitions/utils/transition.ts b/packages/@headlessui-react/src/components/transitions/utils/transition.ts index 6201eae0cb..01d657c2c7 100644 --- a/packages/@headlessui-react/src/components/transitions/utils/transition.ts +++ b/packages/@headlessui-react/src/components/transitions/utils/transition.ts @@ -22,13 +22,13 @@ function waitForTransition(node: HTMLElement, done: (reason: Reason) => void) { // Safari returns a comma separated list of values, so let's sort them and take the highest value. let { transitionDuration, transitionDelay } = getComputedStyle(node) - let [durationMs, delaysMs] = [transitionDuration, transitionDelay].map(value => { + let [durationMs, delaysMs] = [transitionDuration, transitionDelay].map((value) => { let [resolvedValue = 0] = value .split(',') // Remove falsy we can't work with .filter(Boolean) // Values are returned as `0.3s` or `75ms` - .map(v => (v.includes('ms') ? parseFloat(v) : parseFloat(v) * 1000)) + .map((v) => (v.includes('ms') ? parseFloat(v) : parseFloat(v) * 1000)) .sort((a, z) => z - a) return resolvedValue @@ -74,7 +74,7 @@ export function transition( addClasses(node, ...to) d.add( - waitForTransition(node, reason => { + waitForTransition(node, (reason) => { removeClasses(node, ...to, ...base) addClasses(node, ...entered) return _done(reason) diff --git a/packages/@headlessui-react/src/hooks/use-computed.ts b/packages/@headlessui-react/src/hooks/use-computed.ts index 980ef9b420..3d416442d3 100644 --- a/packages/@headlessui-react/src/hooks/use-computed.ts +++ b/packages/@headlessui-react/src/hooks/use-computed.ts @@ -1,12 +1,10 @@ -import { useState, useRef } from 'react' +import { useState } from 'react' import { useIsoMorphicEffect } from './use-iso-morphic-effect' +import { useLatestValue } from './use-latest-value' export function useComputed(cb: () => T, dependencies: React.DependencyList) { let [value, setValue] = useState(cb) - let cbRef = useRef(cb) - useIsoMorphicEffect(() => { - cbRef.current = cb - }, [cb]) + let cbRef = useLatestValue(cb) useIsoMorphicEffect(() => setValue(cbRef.current), [cbRef, setValue, ...dependencies]) return value } diff --git a/packages/@headlessui-react/src/hooks/use-flags.ts b/packages/@headlessui-react/src/hooks/use-flags.ts index 1cb5448e25..7096093a3d 100644 --- a/packages/@headlessui-react/src/hooks/use-flags.ts +++ b/packages/@headlessui-react/src/hooks/use-flags.ts @@ -3,10 +3,10 @@ import { useState, useCallback } from 'react' export function useFlags(initialFlags = 0) { let [flags, setFlags] = useState(initialFlags) - let addFlag = useCallback((flag: number) => setFlags(flags => flags | flag), [setFlags]) + let addFlag = useCallback((flag: number) => setFlags((flags) => flags | flag), [setFlags]) let hasFlag = useCallback((flag: number) => Boolean(flags & flag), [flags]) - let removeFlag = useCallback((flag: number) => setFlags(flags => flags & ~flag), [setFlags]) - let toggleFlag = useCallback((flag: number) => setFlags(flags => flags ^ flag), [setFlags]) + let removeFlag = useCallback((flag: number) => setFlags((flags) => flags & ~flag), [setFlags]) + let toggleFlag = useCallback((flag: number) => setFlags((flags) => flags ^ flag), [setFlags]) return { addFlag, hasFlag, removeFlag, toggleFlag } } diff --git a/packages/@headlessui-react/src/hooks/use-focus-trap.ts b/packages/@headlessui-react/src/hooks/use-focus-trap.ts index 68b4c282ac..fd99685552 100644 --- a/packages/@headlessui-react/src/hooks/use-focus-trap.ts +++ b/packages/@headlessui-react/src/hooks/use-focus-trap.ts @@ -97,7 +97,7 @@ export function useFocusTrap( }, [container, initialFocus, featuresInitialFocus]) // Handle `Tab` & `Shift+Tab` keyboard events - useWindowEvent('keydown', event => { + useWindowEvent('keydown', (event) => { if (!(features & Features.TabLock)) return if (!container.current) return @@ -118,7 +118,7 @@ export function useFocusTrap( // Prevent programmatically escaping the container useWindowEvent( 'focus', - event => { + (event) => { if (!(features & Features.FocusLock)) return let allContainers = new Set(containers?.current) diff --git a/packages/@headlessui-react/src/hooks/use-inert-others.test.tsx b/packages/@headlessui-react/src/hooks/use-inert-others.test.tsx index 15b6f0274e..f03c3c957a 100644 --- a/packages/@headlessui-react/src/hooks/use-inert-others.test.tsx +++ b/packages/@headlessui-react/src/hooks/use-inert-others.test.tsx @@ -17,7 +17,7 @@ it('should be possible to inert other elements', async () => { return (
- +
) } @@ -61,7 +61,7 @@ it('should restore inert elements, when all useInertOthers calls are disabled', return (
- +
) } @@ -136,7 +136,7 @@ it('should restore inert elements, when all useInertOthers calls are disabled (i return (
- +
) @@ -221,7 +221,7 @@ it('should handle inert others correctly when 2 useInertOthers are used in a sha return (
- +
) } diff --git a/packages/@headlessui-react/src/hooks/use-inert-others.ts b/packages/@headlessui-react/src/hooks/use-inert-others.ts index 49537b83e8..a90f87686b 100644 --- a/packages/@headlessui-react/src/hooks/use-inert-others.ts +++ b/packages/@headlessui-react/src/hooks/use-inert-others.ts @@ -42,7 +42,7 @@ export function useInertOthers( } // Collect direct children of the body - document.querySelectorAll('body > *').forEach(child => { + document.querySelectorAll('body > *').forEach((child) => { if (!(child instanceof HTMLElement)) return // Skip non-HTMLElements // Skip the interactables, and the parents of the interactables @@ -71,7 +71,7 @@ export function useInertOthers( // will become inert as well. if (interactables.size > 0) { // Collect direct children of the body - document.querySelectorAll('body > *').forEach(child => { + document.querySelectorAll('body > *').forEach((child) => { if (!(child instanceof HTMLElement)) return // Skip non-HTMLElements // Skip already inert parents diff --git a/packages/@headlessui-react/src/hooks/use-latest-value.ts b/packages/@headlessui-react/src/hooks/use-latest-value.ts new file mode 100644 index 0000000000..6795e7e74b --- /dev/null +++ b/packages/@headlessui-react/src/hooks/use-latest-value.ts @@ -0,0 +1,11 @@ +import { useRef, useEffect } from 'react' + +export function useLatestValue(value: T) { + let cache = useRef(value) + + useEffect(() => { + cache.current = value + }, [value]) + + return cache +} diff --git a/packages/@headlessui-react/src/hooks/use-tree-walker.ts b/packages/@headlessui-react/src/hooks/use-tree-walker.ts index 4dedafb7c1..dfe0123830 100644 --- a/packages/@headlessui-react/src/hooks/use-tree-walker.ts +++ b/packages/@headlessui-react/src/hooks/use-tree-walker.ts @@ -35,6 +35,7 @@ export function useTreeWalker({ let walk = walkRef.current let acceptNode = Object.assign((node: HTMLElement) => accept(node), { acceptNode: accept }) + // @ts-expect-error This `false` is a simple small fix for older browsers let walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, acceptNode, false) while (walker.nextNode()) walk(walker.currentNode as HTMLElement) diff --git a/packages/@headlessui-react/src/index.test.ts b/packages/@headlessui-react/src/index.test.ts index 145b355530..1058a5ed5b 100644 --- a/packages/@headlessui-react/src/index.test.ts +++ b/packages/@headlessui-react/src/index.test.ts @@ -6,6 +6,7 @@ import * as HeadlessUI from './index' */ it('should expose the correct components', () => { expect(Object.keys(HeadlessUI)).toEqual([ + 'Combobox', 'Dialog', 'Disclosure', 'FocusTrap', diff --git a/packages/@headlessui-react/src/index.ts b/packages/@headlessui-react/src/index.ts index 2ef29db23c..2ba6c32e78 100644 --- a/packages/@headlessui-react/src/index.ts +++ b/packages/@headlessui-react/src/index.ts @@ -1,3 +1,4 @@ +export * from './components/combobox/combobox' export * from './components/dialog/dialog' export * from './components/disclosure/disclosure' export * from './components/focus-trap/focus-trap' diff --git a/packages/@headlessui-react/src/test-utils/accessibility-assertions.ts b/packages/@headlessui-react/src/test-utils/accessibility-assertions.ts index 1fb40a1f39..d2ef0479ed 100644 --- a/packages/@headlessui-react/src/test-utils/accessibility-assertions.ts +++ b/packages/@headlessui-react/src/test-utils/accessibility-assertions.ts @@ -91,7 +91,7 @@ export function assertMenuButton( expect(button).toHaveAttribute(attributeName, options.attributes[attributeName]) } } catch (err) { - Error.captureStackTrace(err, assertMenuButton) + if (err instanceof Error) Error.captureStackTrace(err, assertMenuButton) throw err } } @@ -105,7 +105,7 @@ export function assertMenuButtonLinkedWithMenu(button = getMenuButton(), menu = expect(button).toHaveAttribute('aria-controls', menu.getAttribute('id')) expect(menu).toHaveAttribute('aria-labelledby', button.getAttribute('id')) } catch (err) { - Error.captureStackTrace(err, assertMenuButtonLinkedWithMenu) + if (err instanceof Error) Error.captureStackTrace(err, assertMenuButtonLinkedWithMenu) throw err } } @@ -118,7 +118,7 @@ export function assertMenuLinkedWithMenuItem(item: HTMLElement | null, menu = ge // Ensure link between menu & menu item is correct expect(menu).toHaveAttribute('aria-activedescendant', item.getAttribute('id')) } catch (err) { - Error.captureStackTrace(err, assertMenuLinkedWithMenuItem) + if (err instanceof Error) Error.captureStackTrace(err, assertMenuLinkedWithMenuItem) throw err } } @@ -130,7 +130,7 @@ export function assertNoActiveMenuItem(menu = getMenu()) { // Ensure we don't have an active menu expect(menu).not.toHaveAttribute('aria-activedescendant') } catch (err) { - Error.captureStackTrace(err, assertNoActiveMenuItem) + if (err instanceof Error) Error.captureStackTrace(err, assertNoActiveMenuItem) throw err } } @@ -183,7 +183,7 @@ export function assertMenu( assertNever(options.state) } } catch (err) { - Error.captureStackTrace(err, assertMenu) + if (err instanceof Error) Error.captureStackTrace(err, assertMenu) throw err } } @@ -214,7 +214,393 @@ export function assertMenuItem( } } } catch (err) { - Error.captureStackTrace(err, assertMenuItem) + if (err instanceof Error) Error.captureStackTrace(err, assertMenuItem) + throw err + } +} + +// --- + +export function getComboboxLabel(): HTMLElement | null { + return document.querySelector('label,[id^="headlessui-combobox-label"]') +} + +export function getComboboxButton(): HTMLElement | null { + return document.querySelector('button,[role="button"],[id^="headlessui-combobox-button-"]') +} + +export function getComboboxButtons(): HTMLElement[] { + return Array.from(document.querySelectorAll('button,[role="button"]')) +} + +export function getComboboxInput(): HTMLInputElement | null { + return document.querySelector('[role="combobox"]') +} + +export function getCombobox(): HTMLElement | null { + return document.querySelector('[role="listbox"]') +} + +export function getComboboxInputs(): HTMLElement[] { + return Array.from(document.querySelectorAll('[role="combobox"]')) +} + +export function getComboboxes(): HTMLElement[] { + return Array.from(document.querySelectorAll('[role="listbox"]')) +} + +export function getComboboxOptions(): HTMLElement[] { + return Array.from(document.querySelectorAll('[role="option"]')) +} + +// --- + +export enum ComboboxState { + /** The combobox is visible to the user. */ + Visible, + + /** The combobox is **not** visible to the user. It's still in the DOM, but it is hidden. */ + InvisibleHidden, + + /** The combobox is **not** visible to the user. It's not in the DOM, it is unmounted. */ + InvisibleUnmounted, +} + +export function assertCombobox( + options: { + attributes?: Record + textContent?: string + state: ComboboxState + orientation?: 'horizontal' | 'vertical' + }, + combobox = getComboboxInput() +) { + let { orientation = 'vertical' } = options + + try { + switch (options.state) { + case ComboboxState.InvisibleHidden: + if (combobox === null) return expect(combobox).not.toBe(null) + + assertHidden(combobox) + + expect(combobox).toHaveAttribute('aria-labelledby') + expect(combobox).toHaveAttribute('aria-orientation', orientation) + expect(combobox).toHaveAttribute('role', 'combobox') + + if (options.textContent) expect(combobox).toHaveTextContent(options.textContent) + + for (let attributeName in options.attributes) { + expect(combobox).toHaveAttribute(attributeName, options.attributes[attributeName]) + } + break + + case ComboboxState.Visible: + if (combobox === null) return expect(combobox).not.toBe(null) + + assertVisible(combobox) + + expect(combobox).toHaveAttribute('aria-labelledby') + expect(combobox).toHaveAttribute('aria-orientation', orientation) + expect(combobox).toHaveAttribute('role', 'combobox') + + if (options.textContent) expect(combobox).toHaveTextContent(options.textContent) + + for (let attributeName in options.attributes) { + expect(combobox).toHaveAttribute(attributeName, options.attributes[attributeName]) + } + break + + case ComboboxState.InvisibleUnmounted: + expect(combobox).toBe(null) + break + + default: + assertNever(options.state) + } + } catch (err) { + if (err instanceof Error) Error.captureStackTrace(err, assertCombobox) + throw err + } +} + +export function assertComboboxList( + options: { + attributes?: Record + textContent?: string + state: ComboboxState + orientation?: 'horizontal' | 'vertical' + }, + listbox = getCombobox() +) { + let { orientation = 'vertical' } = options + + try { + switch (options.state) { + case ComboboxState.InvisibleHidden: + if (listbox === null) return expect(listbox).not.toBe(null) + + assertHidden(listbox) + + expect(listbox).toHaveAttribute('aria-labelledby') + expect(listbox).toHaveAttribute('aria-orientation', orientation) + expect(listbox).toHaveAttribute('role', 'listbox') + + if (options.textContent) expect(listbox).toHaveTextContent(options.textContent) + + for (let attributeName in options.attributes) { + expect(listbox).toHaveAttribute(attributeName, options.attributes[attributeName]) + } + break + + case ComboboxState.Visible: + if (listbox === null) return expect(listbox).not.toBe(null) + + assertVisible(listbox) + + expect(listbox).toHaveAttribute('aria-labelledby') + expect(listbox).toHaveAttribute('aria-orientation', orientation) + expect(listbox).toHaveAttribute('role', 'listbox') + + if (options.textContent) expect(listbox).toHaveTextContent(options.textContent) + + for (let attributeName in options.attributes) { + expect(listbox).toHaveAttribute(attributeName, options.attributes[attributeName]) + } + break + + case ComboboxState.InvisibleUnmounted: + expect(listbox).toBe(null) + break + + default: + assertNever(options.state) + } + } catch (err) { + if (err instanceof Error) Error.captureStackTrace(err, assertCombobox) + throw err + } +} + +export function assertComboboxButton( + options: { + attributes?: Record + textContent?: string + state: ComboboxState + }, + button = getComboboxButton() +) { + try { + if (button === null) return expect(button).not.toBe(null) + + // Ensure menu button have these properties + expect(button).toHaveAttribute('id') + expect(button).toHaveAttribute('aria-haspopup') + + switch (options.state) { + case ComboboxState.Visible: + expect(button).toHaveAttribute('aria-controls') + expect(button).toHaveAttribute('aria-expanded', 'true') + break + + case ComboboxState.InvisibleHidden: + expect(button).toHaveAttribute('aria-controls') + if (button.hasAttribute('disabled')) { + expect(button).not.toHaveAttribute('aria-expanded') + } else { + expect(button).toHaveAttribute('aria-expanded', 'false') + } + break + + case ComboboxState.InvisibleUnmounted: + expect(button).not.toHaveAttribute('aria-controls') + if (button.hasAttribute('disabled')) { + expect(button).not.toHaveAttribute('aria-expanded') + } else { + expect(button).toHaveAttribute('aria-expanded', 'false') + } + break + + default: + assertNever(options.state) + } + + if (options.textContent) { + expect(button).toHaveTextContent(options.textContent) + } + + // Ensure menu button has the following attributes + for (let attributeName in options.attributes) { + expect(button).toHaveAttribute(attributeName, options.attributes[attributeName]) + } + } catch (err) { + if (err instanceof Error) Error.captureStackTrace(err, assertComboboxButton) + throw err + } +} + +export function assertComboboxLabel( + options: { + attributes?: Record + tag?: string + textContent?: string + }, + label = getComboboxLabel() +) { + try { + if (label === null) return expect(label).not.toBe(null) + + // Ensure menu button have these properties + expect(label).toHaveAttribute('id') + + if (options.textContent) { + expect(label).toHaveTextContent(options.textContent) + } + + if (options.tag) { + expect(label.tagName.toLowerCase()).toBe(options.tag) + } + + // Ensure menu button has the following attributes + for (let attributeName in options.attributes) { + expect(label).toHaveAttribute(attributeName, options.attributes[attributeName]) + } + } catch (err) { + if (err instanceof Error) Error.captureStackTrace(err, assertComboboxLabel) + throw err + } +} + +export function assertComboboxButtonLinkedWithCombobox( + button = getComboboxButton(), + combobox = getCombobox() +) { + try { + if (button === null) return expect(button).not.toBe(null) + if (combobox === null) return expect(combobox).not.toBe(null) + + // Ensure link between button & combobox is correct + expect(button).toHaveAttribute('aria-controls', combobox.getAttribute('id')) + expect(combobox).toHaveAttribute('aria-labelledby', button.getAttribute('id')) + } catch (err) { + if (err instanceof Error) Error.captureStackTrace(err, assertComboboxButtonLinkedWithCombobox) + throw err + } +} + +export function assertComboboxLabelLinkedWithCombobox( + label = getComboboxLabel(), + combobox = getComboboxInput() +) { + try { + if (label === null) return expect(label).not.toBe(null) + if (combobox === null) return expect(combobox).not.toBe(null) + + expect(combobox).toHaveAttribute('aria-labelledby', label.getAttribute('id')) + } catch (err) { + if (err instanceof Error) Error.captureStackTrace(err, assertComboboxLabelLinkedWithCombobox) + throw err + } +} + +export function assertComboboxButtonLinkedWithComboboxLabel( + button = getComboboxButton(), + label = getComboboxLabel() +) { + try { + if (button === null) return expect(button).not.toBe(null) + if (label === null) return expect(label).not.toBe(null) + + // Ensure link between button & label is correct + expect(button).toHaveAttribute('aria-labelledby', `${label.id} ${button.id}`) + } catch (err) { + if (err instanceof Error) + Error.captureStackTrace(err, assertComboboxButtonLinkedWithComboboxLabel) + throw err + } +} + +export function assertActiveComboboxOption( + item: HTMLElement | null, + combobox = getComboboxInput() +) { + try { + if (combobox === null) return expect(combobox).not.toBe(null) + if (item === null) return expect(item).not.toBe(null) + + // Ensure link between combobox & combobox item is correct + expect(combobox).toHaveAttribute('aria-activedescendant', item.getAttribute('id')) + } catch (err) { + if (err instanceof Error) Error.captureStackTrace(err, assertActiveComboboxOption) + throw err + } +} + +export function assertNoActiveComboboxOption(combobox = getComboboxInput()) { + try { + if (combobox === null) return expect(combobox).not.toBe(null) + + // Ensure we don't have an active combobox + expect(combobox).not.toHaveAttribute('aria-activedescendant') + } catch (err) { + if (err instanceof Error) Error.captureStackTrace(err, assertNoActiveComboboxOption) + throw err + } +} + +export function assertNoSelectedComboboxOption(items = getComboboxOptions()) { + try { + for (let item of items) expect(item).not.toHaveAttribute('aria-selected') + } catch (err) { + if (err instanceof Error) Error.captureStackTrace(err, assertNoSelectedComboboxOption) + throw err + } +} + +export function assertComboboxOption( + item: HTMLElement | null, + options?: { + tag?: string + attributes?: Record + selected?: boolean + } +) { + try { + if (item === null) return expect(item).not.toBe(null) + + // Check that some attributes exists, doesn't really matter what the values are at this point in + // time, we just require them. + expect(item).toHaveAttribute('id') + + // Check that we have the correct values for certain attributes + expect(item).toHaveAttribute('role', 'option') + if (!item.getAttribute('aria-disabled')) expect(item).toHaveAttribute('tabindex', '-1') + + // Ensure combobox button has the following attributes + if (!options) return + + for (let attributeName in options.attributes) { + expect(item).toHaveAttribute(attributeName, options.attributes[attributeName]) + } + + if (options.tag) { + expect(item.tagName.toLowerCase()).toBe(options.tag) + } + + if (options.selected != null) { + switch (options.selected) { + case true: + return expect(item).toHaveAttribute('aria-selected', 'true') + + case false: + return expect(item).not.toHaveAttribute('aria-selected') + + default: + assertNever(options.selected) + } + } + } catch (err) { + if (err instanceof Error) Error.captureStackTrace(err, assertComboboxOption) throw err } } @@ -311,7 +697,7 @@ export function assertListbox( assertNever(options.state) } } catch (err) { - Error.captureStackTrace(err, assertListbox) + if (err instanceof Error) Error.captureStackTrace(err, assertListbox) throw err } } @@ -368,7 +754,7 @@ export function assertListboxButton( expect(button).toHaveAttribute(attributeName, options.attributes[attributeName]) } } catch (err) { - Error.captureStackTrace(err, assertListboxButton) + if (err instanceof Error) Error.captureStackTrace(err, assertListboxButton) throw err } } @@ -400,7 +786,7 @@ export function assertListboxLabel( expect(label).toHaveAttribute(attributeName, options.attributes[attributeName]) } } catch (err) { - Error.captureStackTrace(err, assertListboxLabel) + if (err instanceof Error) Error.captureStackTrace(err, assertListboxLabel) throw err } } @@ -417,7 +803,7 @@ export function assertListboxButtonLinkedWithListbox( expect(button).toHaveAttribute('aria-controls', listbox.getAttribute('id')) expect(listbox).toHaveAttribute('aria-labelledby', button.getAttribute('id')) } catch (err) { - Error.captureStackTrace(err, assertListboxButtonLinkedWithListbox) + if (err instanceof Error) Error.captureStackTrace(err, assertListboxButtonLinkedWithListbox) throw err } } @@ -432,7 +818,7 @@ export function assertListboxLabelLinkedWithListbox( expect(listbox).toHaveAttribute('aria-labelledby', label.getAttribute('id')) } catch (err) { - Error.captureStackTrace(err, assertListboxLabelLinkedWithListbox) + if (err instanceof Error) Error.captureStackTrace(err, assertListboxLabelLinkedWithListbox) throw err } } @@ -448,7 +834,8 @@ export function assertListboxButtonLinkedWithListboxLabel( // Ensure link between button & label is correct expect(button).toHaveAttribute('aria-labelledby', `${label.id} ${button.id}`) } catch (err) { - Error.captureStackTrace(err, assertListboxButtonLinkedWithListboxLabel) + if (err instanceof Error) + Error.captureStackTrace(err, assertListboxButtonLinkedWithListboxLabel) throw err } } @@ -461,7 +848,7 @@ export function assertActiveListboxOption(item: HTMLElement | null, listbox = ge // Ensure link between listbox & listbox item is correct expect(listbox).toHaveAttribute('aria-activedescendant', item.getAttribute('id')) } catch (err) { - Error.captureStackTrace(err, assertActiveListboxOption) + if (err instanceof Error) Error.captureStackTrace(err, assertActiveListboxOption) throw err } } @@ -473,7 +860,7 @@ export function assertNoActiveListboxOption(listbox = getListbox()) { // Ensure we don't have an active listbox expect(listbox).not.toHaveAttribute('aria-activedescendant') } catch (err) { - Error.captureStackTrace(err, assertNoActiveListboxOption) + if (err instanceof Error) Error.captureStackTrace(err, assertNoActiveListboxOption) throw err } } @@ -482,7 +869,7 @@ export function assertNoSelectedListboxOption(items = getListboxOptions()) { try { for (let item of items) expect(item).not.toHaveAttribute('aria-selected') } catch (err) { - Error.captureStackTrace(err, assertNoSelectedListboxOption) + if (err instanceof Error) Error.captureStackTrace(err, assertNoSelectedListboxOption) throw err } } @@ -530,7 +917,7 @@ export function assertListboxOption( } } } catch (err) { - Error.captureStackTrace(err, assertListboxOption) + if (err instanceof Error) Error.captureStackTrace(err, assertListboxOption) throw err } } @@ -597,7 +984,7 @@ export function assertSwitch( assertNever(options.state) } } catch (err) { - Error.captureStackTrace(err, assertSwitch) + if (err instanceof Error) Error.captureStackTrace(err, assertSwitch) throw err } } @@ -678,7 +1065,7 @@ export function assertDisclosureButton( expect(button).toHaveAttribute(attributeName, options.attributes[attributeName]) } } catch (err) { - Error.captureStackTrace(err, assertDisclosureButton) + if (err instanceof Error) Error.captureStackTrace(err, assertDisclosureButton) throw err } } @@ -725,7 +1112,7 @@ export function assertDisclosurePanel( assertNever(options.state) } } catch (err) { - Error.captureStackTrace(err, assertDisclosurePanel) + if (err instanceof Error) Error.captureStackTrace(err, assertDisclosurePanel) throw err } } @@ -810,7 +1197,7 @@ export function assertPopoverButton( expect(button).toHaveAttribute(attributeName, options.attributes[attributeName]) } } catch (err) { - Error.captureStackTrace(err, assertPopoverButton) + if (err instanceof Error) Error.captureStackTrace(err, assertPopoverButton) throw err } } @@ -857,7 +1244,7 @@ export function assertPopoverPanel( assertNever(options.state) } } catch (err) { - Error.captureStackTrace(err, assertPopoverPanel) + if (err instanceof Error) Error.captureStackTrace(err, assertPopoverPanel) throw err } } @@ -869,7 +1256,7 @@ export function assertLabelValue(element: HTMLElement | null, value: string) { if (element.hasAttribute('aria-labelledby')) { let ids = element.getAttribute('aria-labelledby')!.split(' ') - expect(ids.map(id => document.getElementById(id)?.textContent).join(' ')).toEqual(value) + expect(ids.map((id) => document.getElementById(id)?.textContent).join(' ')).toEqual(value) return } @@ -984,7 +1371,7 @@ export function assertDialog( assertNever(options.state) } } catch (err) { - Error.captureStackTrace(err, assertDialog) + if (err instanceof Error) Error.captureStackTrace(err, assertDialog) throw err } } @@ -1040,7 +1427,7 @@ export function assertDialogTitle( assertNever(options.state) } } catch (err) { - Error.captureStackTrace(err, assertDialogTitle) + if (err instanceof Error) Error.captureStackTrace(err, assertDialogTitle) throw err } } @@ -1096,7 +1483,7 @@ export function assertDialogDescription( assertNever(options.state) } } catch (err) { - Error.captureStackTrace(err, assertDialogDescription) + if (err instanceof Error) Error.captureStackTrace(err, assertDialogDescription) throw err } } @@ -1143,7 +1530,7 @@ export function assertDialogOverlay( assertNever(options.state) } } catch (err) { - Error.captureStackTrace(err, assertDialogOverlay) + if (err instanceof Error) Error.captureStackTrace(err, assertDialogOverlay) throw err } } @@ -1185,7 +1572,7 @@ export function assertRadioGroupLabel( expect(label).toHaveAttribute(attributeName, options.attributes[attributeName]) } } catch (err) { - Error.captureStackTrace(err, assertRadioGroupLabel) + if (err instanceof Error) Error.captureStackTrace(err, assertRadioGroupLabel) throw err } } @@ -1225,7 +1612,7 @@ export function assertTabs( expect(list).toHaveAttribute('aria-orientation', orientation) let activeTab = Array.from(list.querySelectorAll('[id^="headlessui-tabs-tab-"]'))[active] - let activePanel = panels.find(panel => panel.id === activeTab.getAttribute('aria-controls')) + let activePanel = panels.find((panel) => panel.id === activeTab.getAttribute('aria-controls')) for (let tab of tabs) { expect(tab).toHaveAttribute('id') @@ -1267,7 +1654,7 @@ export function assertTabs( } } } catch (err) { - Error.captureStackTrace(err, assertTabs) + if (err instanceof Error) Error.captureStackTrace(err, assertTabs) throw err } } @@ -1287,7 +1674,7 @@ export function assertActiveElement(element: HTMLElement | null) { expect(document.activeElement?.outerHTML).toBe(element.outerHTML) } } catch (err) { - Error.captureStackTrace(err, assertActiveElement) + if (err instanceof Error) Error.captureStackTrace(err, assertActiveElement) throw err } } @@ -1297,7 +1684,7 @@ export function assertContainsActiveElement(element: HTMLElement | null) { if (element === null) return expect(element).not.toBe(null) expect(element.contains(document.activeElement)).toBe(true) } catch (err) { - Error.captureStackTrace(err, assertContainsActiveElement) + if (err instanceof Error) Error.captureStackTrace(err, assertContainsActiveElement) throw err } } @@ -1311,7 +1698,7 @@ export function assertHidden(element: HTMLElement | null) { expect(element).toHaveAttribute('hidden') expect(element).toHaveStyle({ display: 'none' }) } catch (err) { - Error.captureStackTrace(err, assertHidden) + if (err instanceof Error) Error.captureStackTrace(err, assertHidden) throw err } } @@ -1323,7 +1710,7 @@ export function assertVisible(element: HTMLElement | null) { expect(element).not.toHaveAttribute('hidden') expect(element).not.toHaveStyle({ display: 'none' }) } catch (err) { - Error.captureStackTrace(err, assertVisible) + if (err instanceof Error) Error.captureStackTrace(err, assertVisible) throw err } } @@ -1336,7 +1723,7 @@ export function assertFocusable(element: HTMLElement | null) { expect(isFocusableElement(element, FocusableMode.Strict)).toBe(true) } catch (err) { - Error.captureStackTrace(err, assertFocusable) + if (err instanceof Error) Error.captureStackTrace(err, assertFocusable) throw err } } @@ -1347,7 +1734,7 @@ export function assertNotFocusable(element: HTMLElement | null) { expect(isFocusableElement(element, FocusableMode.Strict)).toBe(false) } catch (err) { - Error.captureStackTrace(err, assertNotFocusable) + if (err instanceof Error) Error.captureStackTrace(err, assertNotFocusable) throw err } } diff --git a/packages/@headlessui-react/src/test-utils/execute-timeline.ts b/packages/@headlessui-react/src/test-utils/execute-timeline.ts index 8b032c1721..0c308a7321 100644 --- a/packages/@headlessui-react/src/test-utils/execute-timeline.ts +++ b/packages/@headlessui-react/src/test-utils/execute-timeline.ts @@ -17,7 +17,7 @@ function redentSnapshot(input: string) { return input .split('\n') - .map(line => + .map((line) => line.trim() === '---' ? line : line.replace(replacer, (_, sign, rest) => `${sign} ${rest}`) ) .join('\n') @@ -69,13 +69,13 @@ export async function executeTimeline( .reduce((total, current) => total + current, 0) // Changes happen in the next frame - await new Promise(resolve => d.nextFrame(resolve)) + await new Promise((resolve) => d.nextFrame(resolve)) // We wait for the amount of the duration - await new Promise(resolve => d.setTimeout(resolve, totalDuration)) + await new Promise((resolve) => d.setTimeout(resolve, totalDuration)) // We wait an additional next frame so that we know that we are done - await new Promise(resolve => d.nextFrame(resolve)) + await new Promise((resolve) => d.nextFrame(resolve)) }, Promise.resolve()) if (snapshots.length <= 0) { @@ -127,7 +127,7 @@ export async function executeTimeline( .replace(/Snapshot Diff:\n/g, '') ) .split('\n') - .map(line => ` ${line}`) + .map((line) => ` ${line}`) .join('\n')}` }) .filter(Boolean) diff --git a/packages/@headlessui-react/src/test-utils/interactions.test.tsx b/packages/@headlessui-react/src/test-utils/interactions.test.tsx index 0e6925fc66..e4701f1556 100644 --- a/packages/@headlessui-react/src/test-utils/interactions.test.tsx +++ b/packages/@headlessui-react/src/test-utils/interactions.test.tsx @@ -175,7 +175,7 @@ describe('Keyboard', () => { await type([key(input)]) - let expected = result.map(e => event(e)) + let expected = result.map((e) => event(e)) expect(fired.length).toEqual(result.length) diff --git a/packages/@headlessui-react/src/test-utils/interactions.ts b/packages/@headlessui-react/src/test-utils/interactions.ts index d78f9b6bd3..71fef368c7 100644 --- a/packages/@headlessui-react/src/test-utils/interactions.ts +++ b/packages/@headlessui-react/src/test-utils/interactions.ts @@ -1,4 +1,7 @@ import { fireEvent } from '@testing-library/react' +import { disposables } from '../utils/disposables' + +let d = disposables() function nextFrame(cb: Function): void { setImmediate(() => @@ -33,7 +36,19 @@ export function shift(event: Partial) { } export function word(input: string): Partial[] { - return input.split('').map(key => ({ key })) + let result = input.split('').map((key) => ({ key })) + + d.enqueue(() => { + let element = document.activeElement + + if (element instanceof HTMLInputElement) { + fireEvent.change(element, { + target: Object.assign({}, element, { value: input }), + }) + } + }) + + return result } let Default = Symbol() @@ -76,6 +91,9 @@ let order: Record< function keypress(element, event) { return fireEvent.keyPress(element, event) }, + function input(element, event) { + return fireEvent.input(element, event) + }, function keyup(element, event) { return fireEvent.keyUp(element, event) }, @@ -134,7 +152,7 @@ export async function type(events: Partial[], element = document. let actions = order[event.key!] ?? order[Default as any] for (let action of actions) { let checks = action.name.split('And') - if (checks.some(check => skip.has(check))) continue + if (checks.some((check) => skip.has(check))) continue let result = action(element, { type: action.name, @@ -159,9 +177,11 @@ export async function type(events: Partial[], element = document. // We don't want to actually wait in our tests, so let's advance jest.runAllTimers() + await d.workQueue() + await new Promise(nextFrame) } catch (err) { - Error.captureStackTrace(err, type) + if (err instanceof Error) Error.captureStackTrace(err, type) throw err } finally { jest.useRealTimers() @@ -224,7 +244,7 @@ export async function click( await new Promise(nextFrame) } catch (err) { - Error.captureStackTrace(err, click) + if (err instanceof Error) Error.captureStackTrace(err, click) throw err } } @@ -237,7 +257,7 @@ export async function focus(element: Document | Element | Window | Node | null) await new Promise(nextFrame) } catch (err) { - Error.captureStackTrace(err, focus) + if (err instanceof Error) Error.captureStackTrace(err, focus) throw err } } @@ -251,7 +271,7 @@ export async function mouseEnter(element: Document | Element | Window | null) { await new Promise(nextFrame) } catch (err) { - Error.captureStackTrace(err, mouseEnter) + if (err instanceof Error) Error.captureStackTrace(err, mouseEnter) throw err } } @@ -265,7 +285,7 @@ export async function mouseMove(element: Document | Element | Window | null) { await new Promise(nextFrame) } catch (err) { - Error.captureStackTrace(err, mouseMove) + if (err instanceof Error) Error.captureStackTrace(err, mouseMove) throw err } } @@ -281,7 +301,7 @@ export async function mouseLeave(element: Document | Element | Window | null) { await new Promise(nextFrame) } catch (err) { - Error.captureStackTrace(err, mouseLeave) + if (err instanceof Error) Error.captureStackTrace(err, mouseLeave) throw err } } @@ -324,8 +344,8 @@ let focusableSelector = [ ? // TODO: Remove this once JSDOM fixes the issue where an element that is // "hidden" can be the document.activeElement, because this is not possible // in real browsers. - selector => `${selector}:not([tabindex='-1']):not([style*='display: none'])` - : selector => `${selector}:not([tabindex='-1'])` + (selector) => `${selector}:not([tabindex='-1']):not([style*='display: none'])` + : (selector) => `${selector}:not([tabindex='-1'])` ) .join(',') diff --git a/packages/@headlessui-react/src/test-utils/suppress-console-logs.ts b/packages/@headlessui-react/src/test-utils/suppress-console-logs.ts index da8e6d1216..0de4a0b4e3 100644 --- a/packages/@headlessui-react/src/test-utils/suppress-console-logs.ts +++ b/packages/@headlessui-react/src/test-utils/suppress-console-logs.ts @@ -5,10 +5,10 @@ type FunctionPropertyNames = { export function suppressConsoleLogs( cb: (...args: T) => unknown, - type: FunctionPropertyNames = 'error' + type: FunctionPropertyNames = 'error' ) { return (...args: T) => { - let spy = jest.spyOn(global.console, type).mockImplementation(jest.fn()) + let spy = jest.spyOn(globalThis.console, type).mockImplementation(jest.fn()) return new Promise((resolve, reject) => { Promise.resolve(cb(...args)).then(resolve, reject) diff --git a/packages/@headlessui-react/src/utils/calculate-active-index.ts b/packages/@headlessui-react/src/utils/calculate-active-index.ts index cc296a9068..16ed66ffb0 100644 --- a/packages/@headlessui-react/src/utils/calculate-active-index.ts +++ b/packages/@headlessui-react/src/utils/calculate-active-index.ts @@ -40,7 +40,7 @@ export function calculateActiveIndex( let nextActiveIndex = (() => { switch (action.focus) { case Focus.First: - return items.findIndex(item => !resolvers.resolveDisabled(item)) + return items.findIndex((item) => !resolvers.resolveDisabled(item)) case Focus.Previous: { let idx = items @@ -64,13 +64,13 @@ export function calculateActiveIndex( let idx = items .slice() .reverse() - .findIndex(item => !resolvers.resolveDisabled(item)) + .findIndex((item) => !resolvers.resolveDisabled(item)) if (idx === -1) return idx return items.length - 1 - idx } case Focus.Specific: - return items.findIndex(item => resolvers.resolveId(item) === action.id) + return items.findIndex((item) => resolvers.resolveId(item) === action.id) case Focus.Nothing: return null diff --git a/packages/@headlessui-react/src/utils/disposables.ts b/packages/@headlessui-react/src/utils/disposables.ts index 7c9a388338..4c0f89c0f8 100644 --- a/packages/@headlessui-react/src/utils/disposables.ts +++ b/packages/@headlessui-react/src/utils/disposables.ts @@ -1,7 +1,12 @@ export function disposables() { let disposables: Function[] = [] + let queue: Function[] = [] let api = { + enqueue(fn: Function) { + queue.push(fn) + }, + requestAnimationFrame(...args: Parameters) { let raf = requestAnimationFrame(...args) api.add(() => cancelAnimationFrame(raf)) @@ -27,6 +32,12 @@ export function disposables() { dispose() } }, + + async workQueue() { + for (let handle of queue.splice(0)) { + await handle() + } + }, } return api diff --git a/packages/@headlessui-react/src/utils/focus-management.ts b/packages/@headlessui-react/src/utils/focus-management.ts index f48158b1da..703e87d5c0 100644 --- a/packages/@headlessui-react/src/utils/focus-management.ts +++ b/packages/@headlessui-react/src/utils/focus-management.ts @@ -18,8 +18,8 @@ let focusableSelector = [ ? // TODO: Remove this once JSDOM fixes the issue where an element that is // "hidden" can be the document.activeElement, because this is not possible // in real browsers. - selector => `${selector}:not([tabindex='-1']):not([style*='display: none'])` - : selector => `${selector}:not([tabindex='-1'])` + (selector) => `${selector}:not([tabindex='-1']):not([style*='display: none'])` + : (selector) => `${selector}:not([tabindex='-1'])` ) .join(',') diff --git a/packages/@headlessui-react/src/utils/match.ts b/packages/@headlessui-react/src/utils/match.ts index 80496d12a2..c4becd32cd 100644 --- a/packages/@headlessui-react/src/utils/match.ts +++ b/packages/@headlessui-react/src/utils/match.ts @@ -12,7 +12,7 @@ export function match `"${key}"`) + .map((key) => `"${key}"`) .join(', ')}.` ) if (Error.captureStackTrace) Error.captureStackTrace(error, match) diff --git a/packages/@headlessui-react/src/utils/render.test.tsx b/packages/@headlessui-react/src/utils/render.test.tsx index cef084a2cd..9c743c4520 100644 --- a/packages/@headlessui-react/src/utils/render.test.tsx +++ b/packages/@headlessui-react/src/utils/render.test.tsx @@ -45,7 +45,7 @@ describe('Default functionality', () => { testRender( - {data => { + {(data) => { expect(data).toBe(slot) return Contents diff --git a/packages/@headlessui-react/src/utils/render.ts b/packages/@headlessui-react/src/utils/render.ts index 1fe004787b..b353e13923 100644 --- a/packages/@headlessui-react/src/utils/render.ts +++ b/packages/@headlessui-react/src/utils/render.ts @@ -102,10 +102,12 @@ function _render( tag: ElementType, name: string ) { - let { as: Component = tag, children, refName = 'ref', ...passThroughProps } = omit(props, [ - 'unmount', - 'static', - ]) + let { + as: Component = tag, + children, + refName = 'ref', + ...passThroughProps + } = omit(props, ['unmount', 'static']) // This allows us to use `` let refRelatedProps = props.ref !== undefined ? { [refName]: props.ref } : {} @@ -132,7 +134,7 @@ function _render( `The current component <${name} /> is rendering a "Fragment".`, `However we need to passthrough the following props:`, Object.keys(passThroughProps) - .map(line => ` - ${line}`) + .map((line) => ` - ${line}`) .join('\n'), '', 'You can apply a few solutions:', @@ -140,7 +142,7 @@ function _render( 'Add an `as="..."` prop, to ensure that we render an actual element instead of a "Fragment".', 'Render a single element as the child so that we can forward the props onto that element.', ] - .map(line => ` - ${line}`) + .map((line) => ` - ${line}`) .join('\n'), ].join('\n') ) @@ -211,7 +213,7 @@ function mergeEventFunctions( export function forwardRefWithAs( component: T ): T & { displayName: string } { - return Object.assign(forwardRef((component as unknown) as any) as any, { + return Object.assign(forwardRef(component as unknown as any) as any, { displayName: component.displayName ?? component.name, }) } diff --git a/packages/@headlessui-react/tsconfig.json b/packages/@headlessui-react/tsconfig.json index cac92c1223..5fb92fde38 100644 --- a/packages/@headlessui-react/tsconfig.json +++ b/packages/@headlessui-react/tsconfig.json @@ -21,13 +21,12 @@ }, "jsx": "preserve", "esModuleInterop": true, - "target": "es5", + "target": "ESNext", "allowJs": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, - "noEmit": true, "resolveJsonModule": true, "isolatedModules": true }, - "exclude": ["node_modules"] + "exclude": ["node_modules", "**/*.test.tsx?"] } diff --git a/packages/@headlessui-react/tsconfig.tsdx.json b/packages/@headlessui-react/tsconfig.tsdx.json deleted file mode 100644 index 1f5d11b1cc..0000000000 --- a/packages/@headlessui-react/tsconfig.tsdx.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "./tsconfig.json", - - "compilerOptions": { - "jsx": "react" - } -} diff --git a/packages/@headlessui-react/tsdx.config.js b/packages/@headlessui-react/tsdx.config.js deleted file mode 100644 index 7ee7a38af3..0000000000 --- a/packages/@headlessui-react/tsdx.config.js +++ /dev/null @@ -1,10 +0,0 @@ -module.exports = { - rollup(config, opts) { - if (opts.format === 'esm') { - config = { ...config, preserveModules: true } - config.output = { ...config.output, dir: 'dist/', entryFileNames: '[name].esm.js' } - delete config.output.file - } - return config - }, -} diff --git a/packages/@headlessui-react/types/jest.d.ts b/packages/@headlessui-react/types/jest.d.ts new file mode 100644 index 0000000000..61902a8f06 --- /dev/null +++ b/packages/@headlessui-react/types/jest.d.ts @@ -0,0 +1,9 @@ +export {} + +declare global { + namespace jest { + interface Matchers { + toBeWithinRenderFrame(actual: number): R + } + } +} diff --git a/packages/@headlessui-vue/.eslintrc.js b/packages/@headlessui-vue/.eslintrc.js deleted file mode 100644 index 48cefd8c41..0000000000 --- a/packages/@headlessui-vue/.eslintrc.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - rules: { - 'react-hooks/rules-of-hooks': 'off', - 'react-hooks/exhaustive-deps': 'off', - }, -} diff --git a/packages/@headlessui-vue/build/index.js b/packages/@headlessui-vue/build/index.js new file mode 100644 index 0000000000..473f46702e --- /dev/null +++ b/packages/@headlessui-vue/build/index.js @@ -0,0 +1,7 @@ +'use strict' + +if (process.env.NODE_ENV === 'production') { + module.exports = require('./headlessui.prod.cjs.js') +} else { + module.exports = require('./headlessui.dev.cjs.js') +} diff --git a/packages/@headlessui-vue/package.json b/packages/@headlessui-vue/package.json index 2f99f390d7..6d26c210d9 100644 --- a/packages/@headlessui-vue/package.json +++ b/packages/@headlessui-vue/package.json @@ -4,12 +4,21 @@ "description": "A set of completely unstyled, fully accessible UI components for Vue 3, designed to integrate beautifully with Tailwind CSS.", "main": "dist/index.js", "typings": "dist/index.d.ts", - "module": "dist/index.esm.js", + "module": "dist/headlessui.esm.js", "license": "MIT", "files": [ "README.md", "dist" ], + "exports": { + ".": { + "import": { + "default": "./dist/headlessui.esm.js" + }, + "require": "./dist/index.js", + "types": "./dist/index.d.ts" + } + }, "sideEffects": false, "engines": { "node": ">=10" @@ -24,17 +33,19 @@ }, "scripts": { "prepublishOnly": "npm run build", - "build": "../../scripts/build.sh", - "watch": "../../scripts/watch.sh", + "build": "../../scripts/build.sh --external:vue", + "watch": "../../scripts/watch.sh --external:vue", "test": "../../scripts/test.sh", - "lint": "../../scripts/lint.sh" + "lint": "../../scripts/lint.sh", + "playground": "yarn workspace playground-vue dev", + "clean": "rimraf ./dist" }, "peerDependencies": { - "vue": "^3.0.0" + "vue": "^3.2.0" }, "devDependencies": { - "@testing-library/vue": "^5.1.0", - "@vue/test-utils": "^2.0.0-beta.7", - "vue": "3.0.7" + "@testing-library/vue": "^5.8.2", + "@vue/test-utils": "^2.0.0-rc.18", + "vue": "^3.2.29" } } diff --git a/packages/@headlessui-vue/postcss.config.js b/packages/@headlessui-vue/postcss.config.js deleted file mode 100644 index 8db70a9528..0000000000 --- a/packages/@headlessui-vue/postcss.config.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('../../postcss.config.js') diff --git a/packages/@headlessui-vue/src/components/combobox/combobox.test.tsx b/packages/@headlessui-vue/src/components/combobox/combobox.test.tsx new file mode 100644 index 0000000000..7e67c93c84 --- /dev/null +++ b/packages/@headlessui-vue/src/components/combobox/combobox.test.tsx @@ -0,0 +1,5196 @@ +import { + DefineComponent, + defineComponent, + nextTick, + ref, + watch, + h, + reactive, + computed, + PropType, +} from 'vue' +import { render } from '../../test-utils/vue-testing-library' +import { + Combobox, + ComboboxInput, + ComboboxLabel, + ComboboxButton, + ComboboxOptions, + ComboboxOption, +} from './combobox' +import { suppressConsoleLogs } from '../../test-utils/suppress-console-logs' +import { + click, + focus, + mouseMove, + mouseLeave, + press, + shift, + type, + word, + Keys, + MouseButton, +} from '../../test-utils/interactions' +import { + assertActiveElement, + assertActiveComboboxOption, + assertComboboxList, + assertComboboxButton, + assertComboboxButtonLinkedWithCombobox, + assertComboboxButtonLinkedWithComboboxLabel, + assertComboboxOption, + assertComboboxLabel, + assertComboboxLabelLinkedWithCombobox, + assertNoActiveComboboxOption, + assertNoSelectedComboboxOption, + getComboboxInput, + getComboboxButton, + getComboboxButtons, + getComboboxInputs, + getComboboxOptions, + getComboboxLabel, + ComboboxState, + getByText, + getComboboxes, +} from '../../test-utils/accessibility-assertions' +import { html } from '../../test-utils/html' +import { useOpenClosedProvider, State, useOpenClosed } from '../../internal/open-closed' + +jest.mock('../../hooks/use-id') + +beforeAll(() => { + jest.spyOn(window, 'requestAnimationFrame').mockImplementation(setImmediate as any) + jest.spyOn(window, 'cancelAnimationFrame').mockImplementation(clearImmediate as any) +}) + +afterAll(() => jest.restoreAllMocks()) + +function nextFrame() { + return new Promise((resolve) => { + requestAnimationFrame(() => { + requestAnimationFrame(() => { + resolve() + }) + }) + }) +} + +function getDefaultComponents() { + return { + Combobox, + ComboboxInput, + ComboboxLabel, + ComboboxButton, + ComboboxOptions, + ComboboxOption, + } +} + +function renderTemplate(input: string | Partial) { + let defaultComponents = getDefaultComponents() + + if (typeof input === 'string') { + return render(defineComponent({ template: input, components: defaultComponents })) + } + + return render( + defineComponent( + Object.assign({}, input, { + components: { ...defaultComponents, ...input.components }, + }) as Parameters[0] + ) + ) +} + +describe('safeguards', () => { + it.each([ + ['ComboboxButton', ComboboxButton], + ['ComboboxLabel', ComboboxLabel], + ['ComboboxOptions', ComboboxOptions], + ['ComboboxOption', ComboboxOption], + ])( + 'should error when we are using a <%s /> without a parent ', + suppressConsoleLogs((name, Component) => { + expect(() => render(Component)).toThrowError( + `<${name} /> is missing a parent component.` + ) + }) + ) + + it( + 'should be possible to render a Combobox without crashing', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + }) + ) +}) + +describe('Rendering', () => { + describe('Combobox', () => { + it( + 'should be possible to render a Combobox using a render prop', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + await click(getComboboxButton()) + + assertComboboxButton({ + state: ComboboxState.Visible, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + + assertComboboxList({ state: ComboboxState.Visible }) + }) + ) + + it( + 'should be possible to disable a Combobox', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + await click(getComboboxButton()) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + await press(Keys.Enter, getComboboxButton()) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + }) + ) + }) + + describe('Combobox.Input', () => { + it( + 'selecting an option puts the value into Combobox.Input when displayValue is not provided', + suppressConsoleLogs(async () => { + let Example = defineComponent({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + // TODO: Rendering Example directly reveals a vue bug — I think it's been fixed for a while but I can't find the commit + renderTemplate(Example) + + await click(getComboboxButton()) + + assertComboboxList({ state: ComboboxState.Visible }) + + await click(getComboboxOptions()[1]) + + expect(getComboboxInput()).toHaveValue('b') + }) + ) + + it( + 'selecting an option puts the display value into Combobox.Input when displayValue is provided', + suppressConsoleLogs(async () => { + let Example = defineComponent({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + renderTemplate(Example) + + await click(getComboboxButton()) + + assertComboboxList({ state: ComboboxState.Visible }) + + await click(getComboboxOptions()[1]) + + expect(getComboboxInput()).toHaveValue('B') + }) + ) + }) + + describe('ComboboxLabel', () => { + it( + 'should be possible to render a ComboboxLabel using a render prop', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + {{JSON.stringify(data)}} + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-3' }, + }) + assertComboboxLabel({ + attributes: { id: 'headlessui-combobox-label-1' }, + textContent: JSON.stringify({ open: false, disabled: false }), + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + await click(getComboboxButton()) + + assertComboboxLabel({ + attributes: { id: 'headlessui-combobox-label-1' }, + textContent: JSON.stringify({ open: true, disabled: false }), + }) + assertComboboxList({ state: ComboboxState.Visible }) + assertComboboxLabelLinkedWithCombobox() + assertComboboxButtonLinkedWithComboboxLabel() + }) + ) + + it( + 'should be possible to render a ComboboxLabel using a render prop and an `as` prop', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + {{JSON.stringify(data)}} + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxLabel({ + attributes: { id: 'headlessui-combobox-label-1' }, + textContent: JSON.stringify({ open: false, disabled: false }), + tag: 'p', + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + await click(getComboboxButton()) + assertComboboxLabel({ + attributes: { id: 'headlessui-combobox-label-1' }, + textContent: JSON.stringify({ open: true, disabled: false }), + tag: 'p', + }) + assertComboboxList({ state: ComboboxState.Visible }) + }) + ) + }) + + describe('ComboboxButton', () => { + it( + 'should be possible to render a ComboboxButton using a render prop', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + {{JSON.stringify(data)}} + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + textContent: JSON.stringify({ open: false, disabled: false }), + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + await click(getComboboxButton()) + + assertComboboxButton({ + state: ComboboxState.Visible, + attributes: { id: 'headlessui-combobox-button-2' }, + textContent: JSON.stringify({ open: true, disabled: false }), + }) + assertComboboxList({ state: ComboboxState.Visible }) + }) + ) + + it( + 'should be possible to render a ComboboxButton using a render prop and an `as` prop', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + {{JSON.stringify(data)}} + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + textContent: JSON.stringify({ open: false, disabled: false }), + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + await click(getComboboxButton()) + + assertComboboxButton({ + state: ComboboxState.Visible, + attributes: { id: 'headlessui-combobox-button-2' }, + textContent: JSON.stringify({ open: true, disabled: false }), + }) + assertComboboxList({ state: ComboboxState.Visible }) + }) + ) + + it( + 'should be possible to render a ComboboxButton and a ComboboxLabel and see them linked together', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + Label + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + await new Promise(requestAnimationFrame) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-3' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + assertComboboxButtonLinkedWithComboboxLabel() + }) + ) + + describe('`type` attribute', () => { + it('should set the `type` to "button" by default', async () => { + renderTemplate({ + template: html` + + + Trigger + + `, + setup: () => ({ value: ref(null) }), + }) + + expect(getComboboxButton()).toHaveAttribute('type', 'button') + }) + + it('should not set the `type` to "button" if it already contains a `type`', async () => { + renderTemplate({ + template: html` + + + Trigger + + `, + setup: () => ({ value: ref(null) }), + }) + + expect(getComboboxButton()).toHaveAttribute('type', 'submit') + }) + + it( + 'should set the `type` to "button" when using the `as` prop which resolves to a "button"', + suppressConsoleLogs(async () => { + let CustomButton = defineComponent({ + setup: (props) => () => h('button', { ...props }), + }) + + renderTemplate({ + template: html` + + + Trigger + + `, + setup: () => ({ + value: ref(null), + CustomButton, + }), + }) + + await new Promise(requestAnimationFrame) + + expect(getComboboxButton()).toHaveAttribute('type', 'button') + }) + ) + + it('should not set the type if the "as" prop is not a "button"', async () => { + renderTemplate({ + template: html` + + + Trigger + + `, + setup: () => ({ value: ref(null) }), + }) + + expect(getComboboxButton()).not.toHaveAttribute('type') + }) + + it( + 'should not set the `type` to "button" when using the `as` prop which resolves to a "div"', + suppressConsoleLogs(async () => { + let CustomButton = defineComponent({ + setup: (props) => () => h('div', props), + }) + + renderTemplate({ + template: html` + + + Trigger + + `, + setup: () => ({ + value: ref(null), + CustomButton, + }), + }) + + await new Promise(requestAnimationFrame) + + expect(getComboboxButton()).not.toHaveAttribute('type') + }) + ) + }) + }) + + describe('ComboboxOptions', () => { + it( + 'should be possible to render ComboboxOptions using a render prop', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + {{JSON.stringify(data)}} + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + await click(getComboboxButton()) + + assertComboboxButton({ + state: ComboboxState.Visible, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + + assertComboboxList({ + state: ComboboxState.Visible, + textContent: JSON.stringify({ open: true }), + }) + + assertActiveElement(getComboboxInput()) + }) + ) + + it('should be possible to always render the ComboboxOptions if we provide it a `static` prop', () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + // Let's verify that the combobox is already there + expect(getComboboxInput()).not.toBe(null) + }) + + it('should be possible to use a different render strategy for the ComboboxOptions', async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + await new Promise(nextTick) + + assertComboboxList({ state: ComboboxState.InvisibleHidden }) + + // Let's open the combobox, to see if it is not hidden anymore + await click(getComboboxButton()) + + assertComboboxList({ state: ComboboxState.Visible }) + }) + }) + + describe('ComboboxOption', () => { + it( + 'should be possible to render a ComboboxOption using a render prop', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + {{JSON.stringify(data)}} + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + await click(getComboboxButton()) + + assertComboboxButton({ + state: ComboboxState.Visible, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ + state: ComboboxState.Visible, + textContent: JSON.stringify({ active: false, selected: false, disabled: false }), + }) + }) + ) + }) + + it('should guarantee the order of DOM nodes when performing actions', async () => { + let props = reactive({ hide: false }) + + renderTemplate({ + template: html` + + + Trigger + + Option 1 + Option 2 + Option 3 + + + `, + setup() { + return { + value: ref(null), + get hide() { + return props.hide + }, + } + }, + }) + + // Open the combobox + await click(getByText('Trigger')) + + props.hide = true + await nextFrame() + + props.hide = false + await nextFrame() + + assertComboboxList({ state: ComboboxState.Visible }) + + let options = getComboboxOptions() + + // Focus the first item + await press(Keys.ArrowDown) + + // Verify that the first combobox option is active + assertActiveComboboxOption(options[0]) + + await press(Keys.ArrowDown) + + // Verify that the second combobox option is active + assertActiveComboboxOption(options[1]) + + await press(Keys.ArrowDown) + + // Verify that the third combobox option is active + assertActiveComboboxOption(options[2]) + }) +}) + +describe('Rendering composition', () => { + it( + 'should be possible to swap the Combobox option with a button for example', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Open combobox + await click(getComboboxButton()) + + // Verify options are buttons now + getComboboxOptions().forEach((option) => assertComboboxOption(option, { tag: 'button' })) + }) + ) +}) + +describe('Composition', () => { + let OpenClosedWrite = defineComponent({ + props: { open: { type: Boolean } }, + setup(props, { slots }) { + useOpenClosedProvider(ref(props.open ? State.Open : State.Closed)) + return () => slots.default?.() + }, + }) + + let OpenClosedRead = defineComponent({ + emits: ['read'], + setup(_, { slots, emit }) { + let state = useOpenClosed() + watch([state], ([value]) => emit('read', value)) + return () => slots.default?.() + }, + }) + + it( + 'should always open the ComboboxOptions because of a wrapping OpenClosed component', + suppressConsoleLogs(async () => { + renderTemplate({ + components: { OpenClosedWrite }, + template: html` + + + Trigger + + {{JSON.stringify(data)}} + + + `, + }) + + await new Promise(nextTick) + + // Verify the combobox is visible + assertComboboxList({ state: ComboboxState.Visible }) + + // Let's try and open the combobox + await click(getComboboxButton()) + + // Verify the combobox is still visible + assertComboboxList({ state: ComboboxState.Visible }) + }) + ) + + it( + 'should always close the ComboboxOptions because of a wrapping OpenClosed component', + suppressConsoleLogs(async () => { + renderTemplate({ + components: { OpenClosedWrite }, + template: html` + + + Trigger + + {{JSON.stringify(data)}} + + + `, + }) + + await new Promise(nextTick) + + // Verify the combobox is hidden + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Let's try and open the combobox + await click(getComboboxButton()) + + // Verify the combobox is still hidden + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + }) + ) + + it( + 'should be possible to read the OpenClosed state', + suppressConsoleLogs(async () => { + let readFn = jest.fn() + renderTemplate({ + components: { OpenClosedRead }, + template: html` + + + Trigger + + + Option A + + + + `, + setup() { + return { value: ref(null), readFn } + }, + }) + + await new Promise(nextTick) + + // Verify the combobox is hidden + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Let's toggle the combobox 3 times + await click(getComboboxButton()) + await click(getComboboxButton()) + await click(getComboboxButton()) + + // Verify the combobox is visible + assertComboboxList({ state: ComboboxState.Visible }) + + expect(readFn).toHaveBeenCalledTimes(3) + expect(readFn).toHaveBeenNthCalledWith(1, State.Open) + expect(readFn).toHaveBeenNthCalledWith(2, State.Closed) + expect(readFn).toHaveBeenNthCalledWith(3, State.Open) + }) + ) +}) + +describe('Keyboard interactions', () => { + describe('Button', () => { + describe('`Enter` key', () => { + it( + 'should be possible to open the Combobox with Enter', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Focus the button + getComboboxButton()?.focus() + + // Open combobox + await press(Keys.Enter) + + // Verify we moved focus to the input field + assertActiveElement(getComboboxInput()) + + // Verify it is visible + assertComboboxButton({ state: ComboboxState.Visible }) + assertComboboxList({ + state: ComboboxState.Visible, + attributes: { id: 'headlessui-combobox-options-3' }, + }) + assertActiveElement(getComboboxInput()) + assertComboboxButtonLinkedWithCombobox() + + // Verify we have combobox options + let options = getComboboxOptions() + expect(options).toHaveLength(3) + options.forEach((option) => assertComboboxOption(option, { selected: false })) + + assertNoActiveComboboxOption() + assertNoSelectedComboboxOption() + }) + ) + + it( + 'should not be possible to open the combobox with Enter when the button is disabled', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Try to focus the button + getComboboxButton()?.focus() + + // Try to open the combobox + await press(Keys.Enter) + + // Verify it is still closed + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + }) + ) + + it( + 'should be possible to open the combobox with Enter, and focus the selected option', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref('b') }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Focus the button + getComboboxButton()?.focus() + + // Open combobox + await press(Keys.Enter) + + // Verify we moved focus to the input field + assertActiveElement(getComboboxInput()) + + // Verify it is visible + assertComboboxButton({ state: ComboboxState.Visible }) + assertComboboxList({ + state: ComboboxState.Visible, + attributes: { id: 'headlessui-combobox-options-3' }, + }) + assertActiveElement(getComboboxInput()) + assertComboboxButtonLinkedWithCombobox() + + // Verify we have combobox options + let options = getComboboxOptions() + expect(options).toHaveLength(3) + options.forEach((option, i) => assertComboboxOption(option, { selected: i === 1 })) + + // Verify that the second combobox option is active (because it is already selected) + assertActiveComboboxOption(options[1]) + }) + ) + + it( + 'should be possible to open the combobox with Enter, and focus the selected option (when using the `hidden` render strategy)', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref('b') }), + }) + + await new Promise(nextTick) + + assertComboboxButton({ + state: ComboboxState.InvisibleHidden, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleHidden }) + + // Focus the button + getComboboxButton()?.focus() + + // Open combobox + await press(Keys.Enter) + + // Verify we moved focus to the input field + assertActiveElement(getComboboxInput()) + + // Verify it is visible + assertComboboxButton({ state: ComboboxState.Visible }) + assertComboboxList({ + state: ComboboxState.Visible, + attributes: { id: 'headlessui-combobox-options-3' }, + }) + assertActiveElement(getComboboxInput()) + assertComboboxButtonLinkedWithCombobox() + + let options = getComboboxOptions() + + // Hover over Option A + await mouseMove(options[0]) + + // Verify that Option A is active + assertActiveComboboxOption(options[0]) + + // Verify that Option B is still selected + assertComboboxOption(options[1], { selected: true }) + + // Close/Hide the combobox + await press(Keys.Escape) + + // Re-open the combobox + await click(getComboboxButton()) + + // Verify we have combobox options + expect(options).toHaveLength(3) + options.forEach((option, i) => assertComboboxOption(option, { selected: i === 1 })) + + // Verify that the second combobox option is active (because it is already selected) + assertActiveComboboxOption(options[1]) + }) + ) + + it( + 'should be possible to open the combobox with Enter, and focus the selected option (with a list of objects)', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + {{ option.name }} + + + `, + setup: () => { + let options = [ + { id: 'a', name: 'Option A' }, + { id: 'b', name: 'Option B' }, + { id: 'c', name: 'Option C' }, + ] + let value = ref(options[1]) + + return { value, options } + }, + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Focus the button + getComboboxButton()?.focus() + + // Open combobox + await press(Keys.Enter) + + // Verify we moved focus to the input field + assertActiveElement(getComboboxInput()) + + // Verify it is visible + assertComboboxButton({ state: ComboboxState.Visible }) + assertComboboxList({ + state: ComboboxState.Visible, + attributes: { id: 'headlessui-combobox-options-3' }, + }) + assertActiveElement(getComboboxInput()) + assertComboboxButtonLinkedWithCombobox() + + // Verify we have combobox options + let options = getComboboxOptions() + expect(options).toHaveLength(3) + options.forEach((option, i) => assertComboboxOption(option, { selected: i === 1 })) + + // Verify that the second combobox option is active (because it is already selected) + assertActiveComboboxOption(options[1]) + }) + ) + + it( + 'should have no active combobox option when there are no combobox options at all', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Focus the button + getComboboxButton()?.focus() + + // Open combobox + await press(Keys.Enter) + + // Verify we moved focus to the input field + assertActiveElement(getComboboxInput()) + + assertComboboxList({ state: ComboboxState.Visible }) + assertActiveElement(getComboboxInput()) + + assertNoActiveComboboxOption() + }) + ) + }) + + describe('`Space` key', () => { + it( + 'should be possible to open the combobox with Space', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Focus the button + getComboboxButton()?.focus() + + // Open combobox + await press(Keys.Space) + + // Verify we moved focus to the input field + assertActiveElement(getComboboxInput()) + + // Verify it is visible + assertComboboxButton({ state: ComboboxState.Visible }) + assertComboboxList({ + state: ComboboxState.Visible, + attributes: { id: 'headlessui-combobox-options-3' }, + }) + assertActiveElement(getComboboxInput()) + assertComboboxButtonLinkedWithCombobox() + + // Verify we have combobox options + let options = getComboboxOptions() + expect(options).toHaveLength(3) + options.forEach((option) => assertComboboxOption(option)) + assertNoActiveComboboxOption() + }) + ) + + it( + 'should not be possible to open the combobox with Space when the button is disabled', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Focus the button + getComboboxButton()?.focus() + + // Try to open the combobox + await press(Keys.Space) + + // Verify it is still closed + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + }) + ) + + it( + 'should be possible to open the combobox with Space, and focus the selected option', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref('b') }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ + state: ComboboxState.InvisibleUnmounted, + }) + + // Focus the button + getComboboxButton()?.focus() + + // Open combobox + await press(Keys.Space) + + // Verify it is visible + assertComboboxButton({ state: ComboboxState.Visible }) + assertComboboxList({ + state: ComboboxState.Visible, + attributes: { id: 'headlessui-combobox-options-3' }, + }) + assertActiveElement(getComboboxInput()) + assertComboboxButtonLinkedWithCombobox() + + // Verify we have combobox options + let options = getComboboxOptions() + expect(options).toHaveLength(3) + options.forEach((option, i) => assertComboboxOption(option, { selected: i === 1 })) + + // Verify that the second combobox option is active (because it is already selected) + assertActiveComboboxOption(options[1]) + }) + ) + + it( + 'should have no active combobox option when there are no combobox options at all', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxList({ + state: ComboboxState.InvisibleUnmounted, + }) + + // Focus the button + getComboboxButton()?.focus() + + // Open combobox + await press(Keys.Space) + assertComboboxList({ state: ComboboxState.Visible }) + assertActiveElement(getComboboxInput()) + + assertNoActiveComboboxOption() + }) + ) + + it( + 'should have no active combobox option upon Space key press, when there are no non-disabled combobox options', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ + state: ComboboxState.InvisibleUnmounted, + }) + + // Focus the button + getComboboxButton()?.focus() + + // Open combobox + await press(Keys.Space) + + assertNoActiveComboboxOption() + }) + ) + }) + + describe('`Escape` key', () => { + it( + 'should be possible to close an open combobox with Escape', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + // Open combobox + await click(getComboboxButton()) + + // Verify it is visible + assertComboboxButton({ state: ComboboxState.Visible }) + assertComboboxList({ + state: ComboboxState.Visible, + attributes: { id: 'headlessui-combobox-options-3' }, + }) + assertActiveElement(getComboboxInput()) + assertComboboxButtonLinkedWithCombobox() + + // Re-focus the button + getComboboxButton()?.focus() + assertActiveElement(getComboboxButton()) + + // Close combobox + await press(Keys.Escape) + + // Verify it is closed + assertComboboxButton({ state: ComboboxState.InvisibleUnmounted }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Verify the input is focused again + assertActiveElement(getComboboxInput()) + }) + ) + }) + + describe('`ArrowDown` key', () => { + it( + 'should be possible to open the combobox with ArrowDown', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref('test') }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Focus the button + getComboboxButton()?.focus() + + // Open combobox + await press(Keys.ArrowDown) + + // Verify it is visible + assertComboboxButton({ state: ComboboxState.Visible }) + assertComboboxList({ + state: ComboboxState.Visible, + attributes: { id: 'headlessui-combobox-options-3' }, + }) + assertActiveElement(getComboboxInput()) + assertComboboxButtonLinkedWithCombobox() + + // Verify we have combobox options + let options = getComboboxOptions() + expect(options).toHaveLength(3) + options.forEach((option) => assertComboboxOption(option)) + + // Verify that the first combobox option is active + assertNoActiveComboboxOption() + }) + ) + + it( + 'should not be possible to open the combobox with ArrowDown when the button is disabled', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Focus the button + getComboboxButton()?.focus() + + // Try to open the combobox + await press(Keys.ArrowDown) + + // Verify it is still closed + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + }) + ) + + it( + 'should be possible to open the combobox with ArrowDown, and focus the selected option', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref('b') }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Focus the button + getComboboxButton()?.focus() + + // Open combobox + await press(Keys.ArrowDown) + + // Verify it is visible + assertComboboxButton({ state: ComboboxState.Visible }) + assertComboboxList({ + state: ComboboxState.Visible, + attributes: { id: 'headlessui-combobox-options-3' }, + }) + assertActiveElement(getComboboxInput()) + assertComboboxButtonLinkedWithCombobox() + + // Verify we have combobox options + let options = getComboboxOptions() + expect(options).toHaveLength(3) + options.forEach((option, i) => assertComboboxOption(option, { selected: i === 1 })) + + // Verify that the second combobox option is active (because it is already selected) + assertActiveComboboxOption(options[1]) + }) + ) + + it( + 'should have no active combobox option when there are no combobox options at all', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Focus the button + getComboboxButton()?.focus() + + // Open combobox + await press(Keys.ArrowDown) + assertComboboxList({ state: ComboboxState.Visible }) + assertActiveElement(getComboboxInput()) + + assertNoActiveComboboxOption() + }) + ) + }) + + describe('`ArrowRight` key', () => { + it( + 'should be possible to open the combobox with ArrowRight', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref('test') }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted, orientation: 'horizontal' }) + + // Focus the button + getComboboxButton()?.focus() + + // Open combobox + await press(Keys.ArrowRight) + + // Verify it is visible + assertComboboxButton({ state: ComboboxState.Visible }) + assertComboboxList({ + state: ComboboxState.Visible, + attributes: { id: 'headlessui-combobox-options-3' }, + orientation: 'horizontal', + }) + assertActiveElement(getComboboxInput()) + assertComboboxButtonLinkedWithCombobox() + + // Verify we have combobox options + let options = getComboboxOptions() + expect(options).toHaveLength(3) + options.forEach((option) => assertComboboxOption(option)) + + // Verify that the first combobox option is active + assertNoActiveComboboxOption() + }) + ) + + it( + 'should not be possible to open the combobox with ArrowRight when the button is disabled', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted, orientation: 'horizontal' }) + + // Focus the button + getComboboxButton()?.focus() + + // Try to open the combobox + await press(Keys.ArrowRight) + + // Verify it is still closed + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted, orientation: 'horizontal' }) + }) + ) + + it( + 'should be possible to open the combobox with ArrowRight, and focus the selected option', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref('b') }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted, orientation: 'horizontal' }) + + // Focus the button + getComboboxButton()?.focus() + + // Open combobox + await press(Keys.ArrowRight) + + // Verify it is visible + assertComboboxButton({ state: ComboboxState.Visible }) + assertComboboxList({ + state: ComboboxState.Visible, + attributes: { id: 'headlessui-combobox-options-3' }, + orientation: 'horizontal', + }) + assertActiveElement(getComboboxInput()) + assertComboboxButtonLinkedWithCombobox() + + // Verify we have combobox options + let options = getComboboxOptions() + expect(options).toHaveLength(3) + options.forEach((option, i) => assertComboboxOption(option, { selected: i === 1 })) + + // Verify that the second combobox option is active (because it is already selected) + assertActiveComboboxOption(options[1]) + }) + ) + + it( + 'should have no active combobox option when there are no combobox options at all', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + + `, + setup: () => ({ value: ref('test') }), + }) + + assertComboboxList({ state: ComboboxState.InvisibleUnmounted, orientation: 'horizontal' }) + + // Focus the button + getComboboxButton()?.focus() + + // Open combobox + await press(Keys.ArrowRight) + assertComboboxList({ state: ComboboxState.Visible, orientation: 'horizontal' }) + assertActiveElement(getComboboxInput()) + + assertNoActiveComboboxOption() + }) + ) + }) + + describe('`ArrowUp` key', () => { + it( + 'should be possible to open the combobox with ArrowUp and the last option should be active', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Focus the button + getComboboxButton()?.focus() + + // Open combobox + await press(Keys.ArrowUp) + + // Verify it is visible + assertComboboxButton({ state: ComboboxState.Visible }) + assertComboboxList({ + state: ComboboxState.Visible, + attributes: { id: 'headlessui-combobox-options-3' }, + }) + assertActiveElement(getComboboxInput()) + assertComboboxButtonLinkedWithCombobox() + + // Verify we have combobox options + let options = getComboboxOptions() + expect(options).toHaveLength(3) + options.forEach((option) => assertComboboxOption(option)) + + // ! ALERT: The LAST option should now be active + assertActiveComboboxOption(options[2]) + }) + ) + + it( + 'should not be possible to open the combobox with ArrowUp and the last option should be active when the button is disabled', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Focus the button + getComboboxButton()?.focus() + + // Try to open the combobox + await press(Keys.ArrowUp) + + // Verify it is still closed + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + }) + ) + + it( + 'should be possible to open the combobox with ArrowUp, and focus the selected option', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref('b') }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Focus the button + getComboboxButton()?.focus() + + // Open combobox + await press(Keys.ArrowUp) + + // Verify it is visible + assertComboboxButton({ state: ComboboxState.Visible }) + assertComboboxList({ + state: ComboboxState.Visible, + attributes: { id: 'headlessui-combobox-options-3' }, + }) + assertActiveElement(getComboboxInput()) + assertComboboxButtonLinkedWithCombobox() + + // Verify we have combobox options + let options = getComboboxOptions() + expect(options).toHaveLength(3) + options.forEach((option, i) => assertComboboxOption(option, { selected: i === 1 })) + + // Verify that the second combobox option is active (because it is already selected) + assertActiveComboboxOption(options[1]) + }) + ) + + it( + 'should have no active combobox option when there are no combobox options at all', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Focus the button + getComboboxButton()?.focus() + + // Open combobox + await press(Keys.ArrowUp) + assertComboboxList({ state: ComboboxState.Visible }) + assertActiveElement(getComboboxInput()) + + assertNoActiveComboboxOption() + }) + ) + + it( + 'should be possible to use ArrowUp to navigate the combobox options and jump to the first non-disabled one', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Focus the button + getComboboxButton()?.focus() + + // Open combobox + await press(Keys.ArrowUp) + + // Verify we have combobox options + let options = getComboboxOptions() + expect(options).toHaveLength(3) + options.forEach((option) => assertComboboxOption(option)) + assertActiveComboboxOption(options[0]) + }) + ) + }) + + describe('`ArrowLeft` key', () => { + it( + 'should be possible to open the combobox with ArrowLeft and the last option should be active', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted, orientation: 'horizontal' }) + + // Focus the button + getComboboxButton()?.focus() + + // Open combobox + await press(Keys.ArrowLeft) + + // Verify it is visible + assertComboboxButton({ state: ComboboxState.Visible }) + assertComboboxList({ + state: ComboboxState.Visible, + attributes: { id: 'headlessui-combobox-options-3' }, + orientation: 'horizontal', + }) + assertActiveElement(getComboboxInput()) + assertComboboxButtonLinkedWithCombobox() + + // Verify we have combobox options + let options = getComboboxOptions() + expect(options).toHaveLength(3) + options.forEach((option) => assertComboboxOption(option)) + + // ! ALERT: The LAST option should now be active + assertActiveComboboxOption(options[2]) + }) + ) + + it( + 'should not be possible to open the combobox with ArrowLeft and the last option should be active when the button is disabled', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted, orientation: 'horizontal' }) + + // Focus the button + getComboboxButton()?.focus() + + // Try to open the combobox + await press(Keys.ArrowLeft) + + // Verify it is still closed + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted, orientation: 'horizontal' }) + }) + ) + + it( + 'should be possible to open the combobox with ArrowLeft, and focus the selected option', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref('b') }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted, orientation: 'horizontal' }) + + // Focus the button + getComboboxButton()?.focus() + + // Open combobox + await press(Keys.ArrowLeft) + + // Verify it is visible + assertComboboxButton({ state: ComboboxState.Visible }) + assertComboboxList({ + state: ComboboxState.Visible, + attributes: { id: 'headlessui-combobox-options-3' }, + orientation: 'horizontal', + }) + assertActiveElement(getComboboxInput()) + assertComboboxButtonLinkedWithCombobox() + + // Verify we have combobox options + let options = getComboboxOptions() + expect(options).toHaveLength(3) + options.forEach((option, i) => assertComboboxOption(option, { selected: i === 1 })) + + // Verify that the second combobox option is active (because it is already selected) + assertActiveComboboxOption(options[1]) + }) + ) + + it( + 'should have no active combobox option when there are no combobox options at all', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + + `, + setup: () => ({ value: ref('test') }), + }) + + assertComboboxList({ state: ComboboxState.InvisibleUnmounted, orientation: 'horizontal' }) + + // Focus the button + getComboboxButton()?.focus() + + // Open combobox + await press(Keys.ArrowLeft) + assertComboboxList({ state: ComboboxState.Visible, orientation: 'horizontal' }) + assertActiveElement(getComboboxInput()) + + assertNoActiveComboboxOption() + }) + ) + + it( + 'should be possible to use ArrowLeft to navigate the combobox options and jump to the first non-disabled one', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted, orientation: 'horizontal' }) + + // Focus the button + getComboboxButton()?.focus() + + // Open combobox + await press(Keys.ArrowLeft) + + // Verify we have combobox options + let options = getComboboxOptions() + expect(options).toHaveLength(3) + options.forEach((option) => assertComboboxOption(option)) + assertActiveComboboxOption(options[0]) + }) + ) + }) + }) + + describe('Input', () => { + describe('`Enter` key', () => { + it( + 'should be possible to close the combobox with Enter and choose the active combobox option', + suppressConsoleLogs(async () => { + let handleChange = jest.fn() + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup() { + let value = ref(null) + watch([value], () => handleChange(value.value)) + return { value } + }, + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Open combobox + await click(getComboboxButton()) + + // Verify it is visible + assertComboboxButton({ state: ComboboxState.Visible }) + + // Activate the first combobox option + let options = getComboboxOptions() + await mouseMove(options[0]) + + // Choose option, and close combobox + await press(Keys.Enter) + + // Verify it is closed + assertComboboxButton({ state: ComboboxState.InvisibleUnmounted }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Verify we got the change event + expect(handleChange).toHaveBeenCalledTimes(1) + expect(handleChange).toHaveBeenCalledWith('a') + + // Verify the button is focused again + assertActiveElement(getComboboxInput()) + + // Open combobox again + await click(getComboboxButton()) + + // Verify the active option is the previously selected one + assertActiveComboboxOption(getComboboxOptions()[0]) + }) + ) + }) + + describe('`Tab` key', () => { + it( + 'pressing Tab should select the active item and move to the next DOM node', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + + Trigger + + Option A + Option B + Option C + + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Open combobox + await click(getComboboxButton()) + + // Select the 2nd option + await press(Keys.ArrowDown) + await press(Keys.ArrowDown) + + // Tab to the next DOM node + await press(Keys.Tab) + + // Verify it is closed + assertComboboxButton({ state: ComboboxState.InvisibleUnmounted }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // That the selected value was the highlighted one + expect(getComboboxInput()?.value).toBe('b') + + // And focus has moved to the next element + assertActiveElement(document.querySelector('#after-combobox')) + }) + ) + + it( + 'pressing Shift+Tab should select the active item and move to the previous DOM node', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + + Trigger + + Option A + Option B + Option C + + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Open combobox + await click(getComboboxButton()) + + // Select the 2nd option + await press(Keys.ArrowDown) + await press(Keys.ArrowDown) + + // Tab to the next DOM node + await press(shift(Keys.Tab)) + + // Verify it is closed + assertComboboxButton({ state: ComboboxState.InvisibleUnmounted }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // That the selected value was the highlighted one + expect(getComboboxInput()?.value).toBe('b') + + // And focus has moved to the next element + assertActiveElement(document.querySelector('#before-combobox')) + }) + ) + }) + + describe('`Escape` key', () => { + it( + 'should be possible to close an open combobox with Escape', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + // Open combobox + await click(getComboboxButton()) + + // Verify it is visible + assertComboboxButton({ state: ComboboxState.Visible }) + assertComboboxList({ + state: ComboboxState.Visible, + attributes: { id: 'headlessui-combobox-options-3' }, + }) + assertActiveElement(getComboboxInput()) + assertComboboxButtonLinkedWithCombobox() + + // Close combobox + await press(Keys.Escape) + + // Verify it is closed + assertComboboxButton({ state: ComboboxState.InvisibleUnmounted }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Verify the button is focused again + assertActiveElement(getComboboxInput()) + }) + ) + }) + + describe('`ArrowDown` key', () => { + it( + 'should be possible to open the combobox with ArrowDown', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref('test') }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Focus the input + getComboboxInput()?.focus() + + // Open combobox + await press(Keys.ArrowDown) + + // Verify it is visible + assertComboboxButton({ state: ComboboxState.Visible }) + assertComboboxList({ + state: ComboboxState.Visible, + attributes: { id: 'headlessui-combobox-options-3' }, + }) + assertActiveElement(getComboboxInput()) + assertComboboxButtonLinkedWithCombobox() + + // Verify we have combobox options + let options = getComboboxOptions() + expect(options).toHaveLength(3) + options.forEach((option) => assertComboboxOption(option)) + + // Verify that the first combobox option is active + assertNoActiveComboboxOption() + }) + ) + + it( + 'should not be possible to open the combobox with ArrowDown when the button is disabled', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Focus the input + getComboboxInput()?.focus() + + // Try to open the combobox + await press(Keys.ArrowDown) + + // Verify it is still closed + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + }) + ) + + it( + 'should be possible to open the combobox with ArrowDown, and focus the selected option', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref('b') }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Focus the input + getComboboxInput()?.focus() + + // Open combobox + await press(Keys.ArrowDown) + + // Verify it is visible + assertComboboxButton({ state: ComboboxState.Visible }) + assertComboboxList({ + state: ComboboxState.Visible, + attributes: { id: 'headlessui-combobox-options-3' }, + }) + assertActiveElement(getComboboxInput()) + assertComboboxButtonLinkedWithCombobox() + + // Verify we have combobox options + let options = getComboboxOptions() + expect(options).toHaveLength(3) + options.forEach((option, i) => assertComboboxOption(option, { selected: i === 1 })) + + // Verify that the second combobox option is active (because it is already selected) + assertActiveComboboxOption(options[1]) + }) + ) + + it( + 'should have no active combobox option when there are no combobox options at all', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Focus the input + getComboboxInput()?.focus() + + // Open combobox + await press(Keys.ArrowDown) + assertComboboxList({ state: ComboboxState.Visible }) + assertActiveElement(getComboboxInput()) + + assertNoActiveComboboxOption() + }) + ) + + it( + 'should be possible to use ArrowDown to navigate the combobox options', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Open combobox + await click(getComboboxButton()) + + // Verify we have combobox options + let options = getComboboxOptions() + expect(options).toHaveLength(3) + options.forEach((option) => assertComboboxOption(option)) + assertNoActiveComboboxOption() + + // We should be able to go down once + await press(Keys.ArrowDown) + assertActiveComboboxOption(options[0]) + + // We should be able to go down again + await press(Keys.ArrowDown) + assertActiveComboboxOption(options[1]) + + // We should be able to go down again + await press(Keys.ArrowDown) + assertActiveComboboxOption(options[2]) + + // We should NOT be able to go down again (because last option). Current implementation won't go around. + await press(Keys.ArrowDown) + assertActiveComboboxOption(options[2]) + }) + ) + + it( + 'should be possible to use ArrowDown to navigate the combobox options and skip the first disabled one', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Open combobox + await click(getComboboxButton()) + + // Verify we have combobox options + let options = getComboboxOptions() + expect(options).toHaveLength(3) + options.forEach((option) => assertComboboxOption(option)) + assertNoActiveComboboxOption() + + // We should be able to go down once + await press(Keys.ArrowDown) + assertActiveComboboxOption(options[1]) + }) + ) + + it( + 'should be possible to use ArrowDown to navigate the combobox options and jump to the first non-disabled one', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Open combobox + await click(getComboboxButton()) + + // Verify we have combobox options + let options = getComboboxOptions() + expect(options).toHaveLength(3) + options.forEach((option) => assertComboboxOption(option)) + assertNoActiveComboboxOption() + + // Open combobox + await press(Keys.ArrowDown) + assertActiveComboboxOption(options[2]) + }) + ) + }) + + describe('`ArrowRight` key', () => { + it( + 'should be possible to open the combobox with ArrowRight', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref('test') }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted, orientation: 'horizontal' }) + + // Focus the input + getComboboxInput()?.focus() + + // Open combobox + await press(Keys.ArrowRight) + + // Verify it is visible + assertComboboxButton({ state: ComboboxState.Visible }) + assertComboboxList({ + state: ComboboxState.Visible, + attributes: { id: 'headlessui-combobox-options-3' }, + orientation: 'horizontal', + }) + assertActiveElement(getComboboxInput()) + assertComboboxButtonLinkedWithCombobox() + + // Verify we have combobox options + let options = getComboboxOptions() + expect(options).toHaveLength(3) + options.forEach((option) => assertComboboxOption(option)) + + // Verify that the first combobox option is active + assertNoActiveComboboxOption() + }) + ) + + it( + 'should not be possible to open the combobox with ArrowRight when the button is disabled', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted, orientation: 'horizontal' }) + + // Focus the input + getComboboxInput()?.focus() + + // Try to open the combobox + await press(Keys.ArrowRight) + + // Verify it is still closed + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted, orientation: 'horizontal' }) + }) + ) + + it( + 'should be possible to open the combobox with ArrowRight, and focus the selected option', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref('b') }), + }) + + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref('test') }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted, orientation: 'horizontal' }) + + // Focus the input + getComboboxInput()?.focus() + + // Open combobox + await press(Keys.ArrowRight) + + // Verify it is visible + assertComboboxButton({ state: ComboboxState.Visible }) + assertComboboxList({ + state: ComboboxState.Visible, + attributes: { id: 'headlessui-combobox-options-3' }, + orientation: 'horizontal', + }) + assertActiveElement(getComboboxInput()) + assertComboboxButtonLinkedWithCombobox() + + // Verify we have combobox options + let options = getComboboxOptions() + expect(options).toHaveLength(3) + options.forEach((option, i) => assertComboboxOption(option, { selected: i === 1 })) + + // Verify that the second combobox option is active (because it is already selected) + assertActiveComboboxOption(options[1]) + }) + ) + + it( + 'should have no active combobox option when there are no combobox options at all', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + + `, + setup: () => ({ value: ref('test') }), + }) + + assertComboboxList({ state: ComboboxState.InvisibleUnmounted, orientation: 'horizontal' }) + + // Focus the input + getComboboxInput()?.focus() + + // Open combobox + await press(Keys.ArrowRight) + assertComboboxList({ state: ComboboxState.Visible, orientation: 'horizontal' }) + assertActiveElement(getComboboxInput()) + + assertNoActiveComboboxOption() + }) + ) + + it( + 'should be possible to use ArrowRight to navigate the combobox options', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref('test') }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted, orientation: 'horizontal' }) + + // Open combobox + await click(getComboboxButton()) + + // Verify we have combobox options + let options = getComboboxOptions() + expect(options).toHaveLength(3) + options.forEach((option) => assertComboboxOption(option)) + assertNoActiveComboboxOption() + + // We should be able to go down once + await press(Keys.ArrowRight) + assertActiveComboboxOption(options[0]) + + // We should be able to go down again + await press(Keys.ArrowRight) + assertActiveComboboxOption(options[1]) + + // We should be able to go down again + await press(Keys.ArrowRight) + assertActiveComboboxOption(options[2]) + + // We should NOT be able to go down again (because last option). Current implementation won't go around. + await press(Keys.ArrowRight) + assertActiveComboboxOption(options[2]) + }) + ) + + it( + 'should be possible to use ArrowRight to navigate the combobox options and skip the first disabled one', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref('test') }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted, orientation: 'horizontal' }) + + // Open combobox + await click(getComboboxButton()) + + // Verify we have combobox options + let options = getComboboxOptions() + expect(options).toHaveLength(3) + options.forEach((option) => assertComboboxOption(option)) + assertNoActiveComboboxOption() + + // We should be able to go down once + await press(Keys.ArrowRight) + assertActiveComboboxOption(options[1]) + }) + ) + + it( + 'should be possible to use ArrowRight to navigate the combobox options and jump to the first non-disabled one', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref('test') }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted, orientation: 'horizontal' }) + + // Open combobox + await click(getComboboxButton()) + + // Verify we have combobox options + let options = getComboboxOptions() + expect(options).toHaveLength(3) + options.forEach((option) => assertComboboxOption(option)) + assertNoActiveComboboxOption() + + // Open combobox + await press(Keys.ArrowRight) + assertActiveComboboxOption(options[2]) + }) + ) + }) + + describe('`ArrowUp` key', () => { + it( + 'should be possible to open the combobox with ArrowUp and the last option should be active', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Focus the input + getComboboxInput()?.focus() + + // Open combobox + await press(Keys.ArrowUp) + + // Verify it is visible + assertComboboxButton({ state: ComboboxState.Visible }) + assertComboboxList({ + state: ComboboxState.Visible, + attributes: { id: 'headlessui-combobox-options-3' }, + }) + assertActiveElement(getComboboxInput()) + assertComboboxButtonLinkedWithCombobox() + + // Verify we have combobox options + let options = getComboboxOptions() + expect(options).toHaveLength(3) + options.forEach((option) => assertComboboxOption(option)) + + // ! ALERT: The LAST option should now be active + assertActiveComboboxOption(options[2]) + }) + ) + + it( + 'should not be possible to open the combobox with ArrowUp and the last option should be active when the button is disabled', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Focus the input + getComboboxInput()?.focus() + + // Try to open the combobox + await press(Keys.ArrowUp) + + // Verify it is still closed + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + }) + ) + + it( + 'should be possible to open the combobox with ArrowUp, and focus the selected option', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref('b') }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Focus the input + getComboboxInput()?.focus() + + // Open combobox + await press(Keys.ArrowUp) + + // Verify it is visible + assertComboboxButton({ state: ComboboxState.Visible }) + assertComboboxList({ + state: ComboboxState.Visible, + attributes: { id: 'headlessui-combobox-options-3' }, + }) + assertActiveElement(getComboboxInput()) + assertComboboxButtonLinkedWithCombobox() + + // Verify we have combobox options + let options = getComboboxOptions() + expect(options).toHaveLength(3) + options.forEach((option, i) => assertComboboxOption(option, { selected: i === 1 })) + + // Verify that the second combobox option is active (because it is already selected) + assertActiveComboboxOption(options[1]) + }) + ) + + it( + 'should have no active combobox option when there are no combobox options at all', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Focus the input + getComboboxInput()?.focus() + + // Open combobox + await press(Keys.ArrowUp) + assertComboboxList({ state: ComboboxState.Visible }) + assertActiveElement(getComboboxInput()) + + assertNoActiveComboboxOption() + }) + ) + + it( + 'should be possible to use ArrowUp to navigate the combobox options and jump to the first non-disabled one', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Focus the input + getComboboxInput()?.focus() + + // Open combobox + await press(Keys.ArrowUp) + + // Verify we have combobox options + let options = getComboboxOptions() + expect(options).toHaveLength(3) + options.forEach((option) => assertComboboxOption(option)) + assertActiveComboboxOption(options[0]) + }) + ) + + it( + 'should not be possible to navigate up or down if there is only a single non-disabled option', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Open combobox + await click(getComboboxButton()) + + // Verify we have combobox options + let options = getComboboxOptions() + expect(options).toHaveLength(3) + options.forEach((option) => assertComboboxOption(option)) + assertNoActiveComboboxOption() + + // Going up or down should select the single available option + await press(Keys.ArrowUp) + + // We should not be able to go up (because those are disabled) + await press(Keys.ArrowUp) + assertActiveComboboxOption(options[2]) + + // We should not be able to go down (because this is the last option) + await press(Keys.ArrowDown) + assertActiveComboboxOption(options[2]) + }) + ) + + it( + 'should be possible to use ArrowUp to navigate the combobox options', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Focus the input + getComboboxInput()?.focus() + + // Open combobox + await press(Keys.ArrowUp) + + // Verify it is visible + assertComboboxButton({ state: ComboboxState.Visible }) + assertComboboxList({ + state: ComboboxState.Visible, + attributes: { id: 'headlessui-combobox-options-3' }, + }) + assertActiveElement(getComboboxInput()) + assertComboboxButtonLinkedWithCombobox() + + // Verify we have combobox options + let options = getComboboxOptions() + expect(options).toHaveLength(3) + options.forEach((option) => assertComboboxOption(option)) + assertActiveComboboxOption(options[2]) + + // We should be able to go down once + await press(Keys.ArrowUp) + assertActiveComboboxOption(options[1]) + + // We should be able to go down again + await press(Keys.ArrowUp) + assertActiveComboboxOption(options[0]) + + // We should NOT be able to go up again (because first option). Current implementation won't go around. + await press(Keys.ArrowUp) + assertActiveComboboxOption(options[0]) + }) + ) + }) + + describe('`ArrowLeft` key', () => { + it( + 'should be possible to open the combobox with ArrowLeft and the last option should be active', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted, orientation: 'horizontal' }) + + // Focus the input + getComboboxInput()?.focus() + + // Open combobox + await press(Keys.ArrowLeft) + + // Verify it is visible + assertComboboxButton({ state: ComboboxState.Visible }) + assertComboboxList({ + state: ComboboxState.Visible, + attributes: { id: 'headlessui-combobox-options-3' }, + orientation: 'horizontal', + }) + assertActiveElement(getComboboxInput()) + assertComboboxButtonLinkedWithCombobox() + + // Verify we have combobox options + let options = getComboboxOptions() + expect(options).toHaveLength(3) + options.forEach((option) => assertComboboxOption(option)) + + // ! ALERT: The LAST option should now be active + assertActiveComboboxOption(options[2]) + }) + ) + + it( + 'should not be possible to open the combobox with ArrowLeft and the last option should be active when the button is disabled', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted, orientation: 'horizontal' }) + + // Focus the input + getComboboxInput()?.focus() + + // Try to open the combobox + await press(Keys.ArrowLeft) + + // Verify it is still closed + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted, orientation: 'horizontal' }) + }) + ) + + it( + 'should be possible to open the combobox with ArrowLeft, and focus the selected option', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref('b') }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted, orientation: 'horizontal' }) + + // Focus the input + getComboboxInput()?.focus() + + // Open combobox + await press(Keys.ArrowLeft) + + // Verify it is visible + assertComboboxButton({ state: ComboboxState.Visible }) + assertComboboxList({ + state: ComboboxState.Visible, + attributes: { id: 'headlessui-combobox-options-3' }, + orientation: 'horizontal', + }) + assertActiveElement(getComboboxInput()) + assertComboboxButtonLinkedWithCombobox() + + // Verify we have combobox options + let options = getComboboxOptions() + expect(options).toHaveLength(3) + options.forEach((option, i) => assertComboboxOption(option, { selected: i === 1 })) + + // Verify that the second combobox option is active (because it is already selected) + assertActiveComboboxOption(options[1]) + }) + ) + + it( + 'should have no active combobox option when there are no combobox options at all', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + + `, + setup: () => ({ value: ref('test') }), + }) + + assertComboboxList({ state: ComboboxState.InvisibleUnmounted, orientation: 'horizontal' }) + + // Focus the input + getComboboxInput()?.focus() + + // Open combobox + await press(Keys.ArrowLeft) + assertComboboxList({ state: ComboboxState.Visible, orientation: 'horizontal' }) + assertActiveElement(getComboboxInput()) + + assertNoActiveComboboxOption() + }) + ) + + it( + 'should be possible to use ArrowLeft to navigate the combobox options and jump to the first non-disabled one', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted, orientation: 'horizontal' }) + + // Focus the input + getComboboxInput()?.focus() + + // Open combobox + await press(Keys.ArrowLeft) + + // Verify we have combobox options + let options = getComboboxOptions() + expect(options).toHaveLength(3) + options.forEach((option) => assertComboboxOption(option)) + assertActiveComboboxOption(options[0]) + }) + ) + }) + + describe('`End` key', () => { + it( + 'should be possible to use the End key to go to the last combobox option', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + // Open combobox + await click(getComboboxButton()) + + let options = getComboboxOptions() + + // We should have no option selected + assertNoActiveComboboxOption() + + // We should be able to go to the last option + await press(Keys.End) + assertActiveComboboxOption(options[2]) + }) + ) + + it( + 'should be possible to use the End key to go to the last non disabled combobox option', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + Option D + + + `, + setup: () => ({ value: ref(null) }), + }) + + // Open combobox + await click(getComboboxButton()) + + let options = getComboboxOptions() + + // We should have no option selected + assertNoActiveComboboxOption() + + // We should be able to go to the last non-disabled option + await press(Keys.End) + assertActiveComboboxOption(options[1]) + }) + ) + + it( + 'should be possible to use the End key to go to the first combobox option if that is the only non-disabled combobox option', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + Option D + + + `, + setup: () => ({ value: ref(null) }), + }) + + // Open combobox + await click(getComboboxButton()) + + // We opened via click, we don't have an active option + assertNoActiveComboboxOption() + + // We should not be able to go to the end + await press(Keys.End) + + let options = getComboboxOptions() + assertActiveComboboxOption(options[0]) + }) + ) + + it( + 'should have no active combobox option upon End key press, when there are no non-disabled combobox options', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + Option D + + + `, + setup: () => ({ value: ref(null) }), + }) + + // Open combobox + await click(getComboboxButton()) + + // We opened via click, we don't have an active option + assertNoActiveComboboxOption() + + // We should not be able to go to the end + await press(Keys.End) + + assertNoActiveComboboxOption() + }) + ) + }) + + describe('`PageDown` key', () => { + it( + 'should be possible to use the PageDown key to go to the last combobox option', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + // Open combobox + await click(getComboboxButton()) + + let options = getComboboxOptions() + + // We should be on the first option + assertNoActiveComboboxOption() + + // We should be able to go to the last option + await press(Keys.PageDown) + assertActiveComboboxOption(options[2]) + }) + ) + + it( + 'should be possible to use the PageDown key to go to the last non disabled Combobox option', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + Option D + + + `, + setup: () => ({ value: ref(null) }), + }) + + // Open combobox + await click(getComboboxButton()) + + // Open combobox + await press(Keys.Space) + + let options = getComboboxOptions() + + // We should have nothing active + assertNoActiveComboboxOption() + + // We should be able to go to the last non-disabled option + await press(Keys.PageDown) + assertActiveComboboxOption(options[1]) + }) + ) + + it( + 'should be possible to use the PageDown key to go to the first combobox option if that is the only non-disabled combobox option', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + Option D + + + `, + setup: () => ({ value: ref(null) }), + }) + + // Open combobox + await click(getComboboxButton()) + + // We opened via click, we don't have an active option + assertNoActiveComboboxOption() + + // We should not be able to go to the end + await press(Keys.PageDown) + + let options = getComboboxOptions() + assertActiveComboboxOption(options[0]) + }) + ) + + it( + 'should have no active combobox option upon PageDown key press, when there are no non-disabled combobox options', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + Option D + + + `, + setup: () => ({ value: ref(null) }), + }) + + // Open combobox + await click(getComboboxButton()) + + // We opened via click, we don't have an active option + assertNoActiveComboboxOption() + + // We should not be able to go to the end + await press(Keys.PageDown) + + assertNoActiveComboboxOption() + }) + ) + }) + + describe('`Home` key', () => { + it( + 'should be possible to use the Home key to go to the first combobox option', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + // Focus the input + getComboboxInput()?.focus() + + // Open combobox + await press(Keys.ArrowUp) + + let options = getComboboxOptions() + + // We should be on the last option + assertActiveComboboxOption(options[2]) + + // We should be able to go to the first option + await press(Keys.Home) + assertActiveComboboxOption(options[0]) + }) + ) + + it( + 'should be possible to use the Home key to go to the first non disabled combobox option', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + Option D + + + `, + setup: () => ({ value: ref(null) }), + }) + + // Open combobox + await click(getComboboxButton()) + + // We opened via click, we don't have an active option + assertNoActiveComboboxOption() + + // We should not be able to go to the end + await press(Keys.Home) + + let options = getComboboxOptions() + + // We should be on the first non-disabled option + assertActiveComboboxOption(options[2]) + }) + ) + + it( + 'should be possible to use the Home key to go to the last combobox option if that is the only non-disabled combobox option', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + Option D + + + `, + setup: () => ({ value: ref(null) }), + }) + + // Open combobox + await click(getComboboxButton()) + + // We opened via click, we don't have an active option + assertNoActiveComboboxOption() + + // We should not be able to go to the end + await press(Keys.Home) + + let options = getComboboxOptions() + assertActiveComboboxOption(options[3]) + }) + ) + + it( + 'should have no active combobox option upon Home key press, when there are no non-disabled combobox options', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + Option D + + + `, + setup: () => ({ value: ref(null) }), + }) + + // Open combobox + await click(getComboboxButton()) + + // We opened via click, we don't have an active option + assertNoActiveComboboxOption() + + // We should not be able to go to the end + await press(Keys.Home) + + assertNoActiveComboboxOption() + }) + ) + }) + + describe('`PageUp` key', () => { + it( + 'should be possible to use the PageUp key to go to the first combobox option', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + // Focus the input + getComboboxInput()?.focus() + + // Open combobox + await press(Keys.ArrowUp) + + let options = getComboboxOptions() + + // We should be on the last option + assertActiveComboboxOption(options[2]) + + // We should be able to go to the first option + await press(Keys.PageUp) + assertActiveComboboxOption(options[0]) + }) + ) + + it( + 'should be possible to use the PageUp key to go to the first non disabled combobox option', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + Option D + + + `, + setup: () => ({ value: ref(null) }), + }) + + // Open combobox + await click(getComboboxButton()) + + // We opened via click, we don't have an active option + assertNoActiveComboboxOption() + + // We should not be able to go to the end + await press(Keys.PageUp) + + let options = getComboboxOptions() + + // We should be on the first non-disabled option + assertActiveComboboxOption(options[2]) + }) + ) + + it( + 'should be possible to use the PageUp key to go to the last combobox option if that is the only non-disabled combobox option', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + Option D + + + `, + setup: () => ({ value: ref(null) }), + }) + + // Open combobox + await click(getComboboxButton()) + + // We opened via click, we don't have an active option + assertNoActiveComboboxOption() + + // We should not be able to go to the end + await press(Keys.PageUp) + + let options = getComboboxOptions() + assertActiveComboboxOption(options[3]) + }) + ) + + it( + 'should have no active combobox option upon PageUp key press, when there are no non-disabled combobox options', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + Option D + + + `, + setup: () => ({ value: ref(null) }), + }) + + // Open combobox + await click(getComboboxButton()) + + // We opened via click, we don't have an active option + assertNoActiveComboboxOption() + + // We should not be able to go to the end + await press(Keys.PageUp) + + assertNoActiveComboboxOption() + }) + ) + }) + + describe('`Any` key aka search', () => { + let Example = defineComponent({ + components: getDefaultComponents(), + + template: html` + + + Trigger + + + {{ person.name }} + + + + `, + + props: { + people: { + type: Array as PropType<{ value: string; name: string; disabled: boolean }[]>, + required: true, + }, + }, + + setup(props) { + let value = ref(null) + let query = ref('') + let filteredPeople = computed(() => { + return query.value === '' + ? props.people + : props.people.filter((person) => + person.name.toLowerCase().includes(query.value.toLowerCase()) + ) + }) + + return { + value, + query, + filteredPeople, + setQuery: (event: Event & { target: HTMLInputElement }) => { + query.value = event.target.value + }, + } + }, + }) + + it( + 'should be possible to type a full word that has a perfect match', + suppressConsoleLogs(async () => { + renderTemplate({ + components: { Example }, + template: html` + + `, + }) + + // Open combobox + await click(getComboboxButton()) + + // Verify we moved focus to the input field + assertActiveElement(getComboboxInput()) + let options: ReturnType + + // We should be able to go to the second option + await type(word('bob')) + await press(Keys.Home) + + options = getComboboxOptions() + expect(options).toHaveLength(1) + expect(options[0]).toHaveTextContent('bob') + assertActiveComboboxOption(options[0]) + + // We should be able to go to the first option + await type(word('alice')) + await press(Keys.Home) + + options = getComboboxOptions() + expect(options).toHaveLength(1) + expect(options[0]).toHaveTextContent('alice') + assertActiveComboboxOption(options[0]) + + // We should be able to go to the last option + await type(word('charlie')) + await press(Keys.Home) + + options = getComboboxOptions() + expect(options).toHaveLength(1) + expect(options[0]).toHaveTextContent('charlie') + assertActiveComboboxOption(options[0]) + }) + ) + + it( + 'should be possible to type a partial of a word', + suppressConsoleLogs(async () => { + renderTemplate({ + components: { Example }, + template: html` + + `, + }) + + // Open combobox + await click(getComboboxButton()) + + let options: ReturnType + + // We should be able to go to the second option + await type(word('bo')) + await press(Keys.Home) + options = getComboboxOptions() + expect(options).toHaveLength(1) + expect(options[0]).toHaveTextContent('bob') + assertActiveComboboxOption(options[0]) + + // We should be able to go to the first option + await type(word('ali')) + await press(Keys.Home) + options = getComboboxOptions() + expect(options).toHaveLength(1) + expect(options[0]).toHaveTextContent('alice') + assertActiveComboboxOption(options[0]) + + // We should be able to go to the last option + await type(word('char')) + await press(Keys.Home) + options = getComboboxOptions() + expect(options).toHaveLength(1) + expect(options[0]).toHaveTextContent('charlie') + assertActiveComboboxOption(options[0]) + }) + ) + + it( + 'should be possible to type words with spaces', + suppressConsoleLogs(async () => { + renderTemplate({ + components: { Example }, + template: html` + + `, + }) + + // Open combobox + await click(getComboboxButton()) + + let options: ReturnType + + // We should be able to go to the second option + await type(word('bob t')) + await press(Keys.Home) + options = getComboboxOptions() + expect(options).toHaveLength(1) + expect(options[0]).toHaveTextContent('bob the builder') + assertActiveComboboxOption(options[0]) + + // We should be able to go to the first option + await type(word('alice j')) + await press(Keys.Home) + options = getComboboxOptions() + expect(options).toHaveLength(1) + expect(options[0]).toHaveTextContent('alice jones') + assertActiveComboboxOption(options[0]) + + // We should be able to go to the last option + await type(word('charlie b')) + await press(Keys.Home) + options = getComboboxOptions() + expect(options).toHaveLength(1) + expect(options[0]).toHaveTextContent('charlie bit me') + assertActiveComboboxOption(options[0]) + }) + ) + + it( + 'should not be possible to search and activate a disabled option', + suppressConsoleLogs(async () => { + renderTemplate({ + components: { Example }, + template: html` + + `, + }) + + // Open combobox + await click(getComboboxButton()) + + // We should not be able to go to the disabled option + await type(word('bo')) + await press(Keys.Home) + + assertNoActiveComboboxOption() + assertNoSelectedComboboxOption() + }) + ) + + it( + 'should maintain activeIndex and activeOption when filtering', + suppressConsoleLogs(async () => { + renderTemplate({ + components: { Example }, + template: html` + + `, + }) + + // Open combobox + await click(getComboboxButton()) + + let options: ReturnType + + await press(Keys.ArrowDown) + await press(Keys.ArrowDown) + + // Person B should be active + options = getComboboxOptions() + expect(options[1]).toHaveTextContent('person b') + assertActiveComboboxOption(options[1]) + + // Filter more, remove `person a` + await type(word('person b')) + options = getComboboxOptions() + expect(options[0]).toHaveTextContent('person b') + assertActiveComboboxOption(options[0]) + + // Filter less, insert `person a` before `person b` + await type(word('person')) + options = getComboboxOptions() + expect(options[1]).toHaveTextContent('person b') + assertActiveComboboxOption(options[1]) + }) + ) + }) + }) +}) + +describe('Mouse interactions', () => { + it( + 'should focus the ComboboxButton when we click the ComboboxLabel', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + Label + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + // Ensure the button is not focused yet + assertActiveElement(document.body) + + // Focus the label + await click(getComboboxLabel()) + + // Ensure that the actual button is focused instead + assertActiveElement(getComboboxInput()) + }) + ) + + it( + 'should not focus the ComboboxInput when we right click the ComboboxLabel', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + Label + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + // Ensure the button is not focused yet + assertActiveElement(document.body) + + // Focus the label + await click(getComboboxLabel(), MouseButton.Right) + + // Ensure that the body is still active + assertActiveElement(document.body) + }) + ) + + it( + 'should be possible to open the combobox on click', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Open combobox + await click(getComboboxButton()) + + // Verify it is visible + assertComboboxButton({ state: ComboboxState.Visible }) + assertComboboxList({ + state: ComboboxState.Visible, + attributes: { id: 'headlessui-combobox-options-3' }, + }) + assertActiveElement(getComboboxInput()) + assertComboboxButtonLinkedWithCombobox() + + // Verify we have combobox options + let options = getComboboxOptions() + expect(options).toHaveLength(3) + options.forEach((option) => assertComboboxOption(option)) + }) + ) + + it( + 'should not be possible to open the combobox on right click', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Try to open the combobox + await click(getComboboxButton(), MouseButton.Right) + + // Verify it is still closed + assertComboboxButton({ state: ComboboxState.InvisibleUnmounted }) + }) + ) + + it( + 'should not be possible to open the combobox on click when the button is disabled', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Try to open the combobox + await click(getComboboxButton()) + + // Verify it is still closed + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + }) + ) + + it( + 'should be possible to open the combobox on click, and focus the selected option', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref('b') }), + }) + + assertComboboxButton({ + state: ComboboxState.InvisibleUnmounted, + attributes: { id: 'headlessui-combobox-button-2' }, + }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Open combobox + await click(getComboboxButton()) + + // Verify it is visible + assertComboboxButton({ state: ComboboxState.Visible }) + assertComboboxList({ + state: ComboboxState.Visible, + attributes: { id: 'headlessui-combobox-options-3' }, + }) + assertActiveElement(getComboboxInput()) + assertComboboxButtonLinkedWithCombobox() + + // Verify we have combobox options + let options = getComboboxOptions() + expect(options).toHaveLength(3) + options.forEach((option, i) => assertComboboxOption(option, { selected: i === 1 })) + + // Verify that the second combobox option is active (because it is already selected) + assertActiveComboboxOption(options[1]) + }) + ) + + it( + 'should be possible to close a combobox on click', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(null) }), + }) + + // Open combobox + await click(getComboboxButton()) + + // Verify it is visible + assertComboboxButton({ state: ComboboxState.Visible }) + + // Click to close + await click(getComboboxButton()) + + // Verify it is closed + assertComboboxButton({ state: ComboboxState.InvisibleUnmounted }) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + }) + ) + + it( + 'should be a no-op when we click outside of a closed combobox', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + alice + bob + charlie + + + `, + setup: () => ({ value: ref(null) }), + }) + + // Verify that the window is closed + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Click something that is not related to the combobox + await click(document.body) + + // Should still be closed + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + }) + ) + + it( + 'should be possible to click outside of the combobox which should close the combobox', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + alice + bob + charlie + + + `, + setup: () => ({ value: ref(null) }), + }) + + // Open combobox + await click(getComboboxButton()) + assertComboboxList({ state: ComboboxState.Visible }) + assertActiveElement(getComboboxInput()) + + // Click something that is not related to the combobox + await click(document.body) + + // Should be closed now + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Verify the input is focused again + assertActiveElement(getComboboxInput()) + }) + ) + + it( + 'should be possible to click outside of the combobox on another combobox button which should close the current combobox and open the new combobox', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` +
+ + + Trigger + + alice + bob + charlie + + + + + + Trigger + + alice + bob + charlie + + +
+ `, + setup: () => ({ value: ref(null) }), + }) + + let [button1, button2] = getComboboxButtons() + + // Click the first combobox button + await click(button1) + expect(getComboboxes()).toHaveLength(1) // Only 1 combobox should be visible + + // Verify that the first input is focused + assertActiveElement(getComboboxInputs()[0]) + + // Click the second combobox button + await click(button2) + + expect(getComboboxes()).toHaveLength(1) // Only 1 combobox should be visible + + // Verify that the first input is focused + assertActiveElement(getComboboxInputs()[1]) + }) + ) + + it( + 'should be possible to click outside of the combobox which should close the combobox (even if we press the combobox button)', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + alice + bob + charlie + + + `, + setup: () => ({ value: ref(null) }), + }) + + // Open combobox + await click(getComboboxButton()) + assertComboboxList({ state: ComboboxState.Visible }) + assertActiveElement(getComboboxInput()) + + // Click the combobox button again + await click(getComboboxButton()) + + // Should be closed now + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Verify the input is focused again + assertActiveElement(getComboboxInput()) + }) + ) + + it( + 'should be possible to click outside of the combobox, on an element which is within a focusable element, which closes the combobox', + suppressConsoleLogs(async () => { + let focusFn = jest.fn() + renderTemplate({ + template: html` +
+ + + Trigger + + alice + bob + charlie + + + + +
+ `, + setup: () => ({ value: ref('test'), focusFn }), + }) + + // Click the combobox button + await click(getComboboxButton()) + + // Ensure the combobox is open + assertComboboxList({ state: ComboboxState.Visible }) + + // Click the span inside the button + await click(getByText('Next')) + + // Ensure the combobox is closed + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + + // Ensure the outside button is focused + assertActiveElement(document.getElementById('btn')) + + // Ensure that the focus button only got focus once (first click) + expect(focusFn).toHaveBeenCalledTimes(1) + }) + ) + + it( + 'should be possible to hover an option and make it active', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + alice + bob + charlie + + + `, + setup: () => ({ value: ref(null) }), + }) + + // Open combobox + await click(getComboboxButton()) + + let options = getComboboxOptions() + // We should be able to go to the second option + await mouseMove(options[1]) + assertActiveComboboxOption(options[1]) + + // We should be able to go to the first option + await mouseMove(options[0]) + assertActiveComboboxOption(options[0]) + + // We should be able to go to the last option + await mouseMove(options[2]) + assertActiveComboboxOption(options[2]) + }) + ) + + it( + 'should make a combobox option active when you move the mouse over it', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + alice + bob + charlie + + + `, + setup: () => ({ value: ref(null) }), + }) + + // Open combobox + await click(getComboboxButton()) + + let options = getComboboxOptions() + // We should be able to go to the second option + await mouseMove(options[1]) + assertActiveComboboxOption(options[1]) + }) + ) + + it( + 'should be a no-op when we move the mouse and the combobox option is already active', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + alice + bob + charlie + + + `, + setup: () => ({ value: ref(null) }), + }) + + // Open combobox + await click(getComboboxButton()) + + let options = getComboboxOptions() + + // We should be able to go to the second option + await mouseMove(options[1]) + assertActiveComboboxOption(options[1]) + + await mouseMove(options[1]) + + // Nothing should be changed + assertActiveComboboxOption(options[1]) + }) + ) + + it( + 'should be a no-op when we move the mouse and the combobox option is disabled', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + alice + bob + charlie + + + `, + setup: () => ({ value: ref(null) }), + }) + + // Open combobox + await click(getComboboxButton()) + + let options = getComboboxOptions() + + await mouseMove(options[1]) + assertNoActiveComboboxOption() + }) + ) + + it( + 'should not be possible to hover an option that is disabled', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + alice + bob + charlie + + + `, + setup: () => ({ value: ref(null) }), + }) + + // Open combobox + await click(getComboboxButton()) + + let options = getComboboxOptions() + + // Try to hover over option 1, which is disabled + await mouseMove(options[1]) + + // We should not have an active option now + assertNoActiveComboboxOption() + }) + ) + + it( + 'should be possible to mouse leave an option and make it inactive', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + alice + bob + charlie + + + `, + setup: () => ({ value: ref(null) }), + }) + + // Open combobox + await click(getComboboxButton()) + + let options = getComboboxOptions() + + // We should be able to go to the second option + await mouseMove(options[1]) + assertActiveComboboxOption(options[1]) + + await mouseLeave(options[1]) + assertNoActiveComboboxOption() + + // We should be able to go to the first option + await mouseMove(options[0]) + assertActiveComboboxOption(options[0]) + + await mouseLeave(options[0]) + assertNoActiveComboboxOption() + + // We should be able to go to the last option + await mouseMove(options[2]) + assertActiveComboboxOption(options[2]) + + await mouseLeave(options[2]) + assertNoActiveComboboxOption() + }) + ) + + it( + 'should be possible to mouse leave a disabled option and be a no-op', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + alice + bob + charlie + + + `, + setup: () => ({ value: ref(null) }), + }) + + // Open combobox + await click(getComboboxButton()) + + let options = getComboboxOptions() + + // Try to hover over option 1, which is disabled + await mouseMove(options[1]) + assertNoActiveComboboxOption() + + await mouseLeave(options[1]) + assertNoActiveComboboxOption() + }) + ) + + it( + 'should be possible to click a combobox option, which closes the combobox', + suppressConsoleLogs(async () => { + let handleChange = jest.fn() + renderTemplate({ + template: html` + + + Trigger + + alice + bob + charlie + + + `, + setup() { + let value = ref(null) + watch([value], () => handleChange(value.value)) + return { value } + }, + }) + + // Open combobox + await click(getComboboxButton()) + assertComboboxList({ state: ComboboxState.Visible }) + assertActiveElement(getComboboxInput()) + + let options = getComboboxOptions() + + // We should be able to click the first option + await click(options[1]) + assertComboboxList({ state: ComboboxState.InvisibleUnmounted }) + expect(handleChange).toHaveBeenCalledTimes(1) + expect(handleChange).toHaveBeenCalledWith('bob') + + // Verify the input is focused again + assertActiveElement(getComboboxInput()) + + // Open combobox again + await click(getComboboxButton()) + + // Verify the active option is the previously selected one + assertActiveComboboxOption(getComboboxOptions()[1]) + }) + ) + + it( + 'should be possible to click a disabled combobox option, which is a no-op', + suppressConsoleLogs(async () => { + let handleChange = jest.fn() + renderTemplate({ + template: html` + + + Trigger + + alice + bob + charlie + + + `, + setup() { + let value = ref(null) + watch([value], () => handleChange(value.value)) + return { value } + }, + }) + + // Open combobox + await click(getComboboxButton()) + assertComboboxList({ state: ComboboxState.Visible }) + assertActiveElement(getComboboxInput()) + + let options = getComboboxOptions() + + // We should be able to click the first option + await click(options[1]) + assertComboboxList({ state: ComboboxState.Visible }) + assertActiveElement(getComboboxInput()) + expect(handleChange).toHaveBeenCalledTimes(0) + + // Close the combobox + await click(getComboboxButton()) + + // Open combobox again + await click(getComboboxButton()) + + // Verify the active option is non existing + assertNoActiveComboboxOption() + }) + ) + + it( + 'should be possible focus a combobox option, so that it becomes active', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + alice + bob + charlie + + + `, + setup: () => ({ value: ref(null) }), + }) + + // Open combobox + await click(getComboboxButton()) + assertComboboxList({ state: ComboboxState.Visible }) + assertActiveElement(getComboboxInput()) + + let options = getComboboxOptions() + + // Verify that nothing is active yet + assertNoActiveComboboxOption() + + // We should be able to focus the first option + await focus(options[1]) + assertActiveComboboxOption(options[1]) + }) + ) + + it( + 'should not be possible to focus a combobox option which is disabled', + suppressConsoleLogs(async () => { + renderTemplate({ + template: html` + + + Trigger + + alice + bob + charlie + + + `, + setup: () => ({ value: ref(null) }), + }) + + // Open combobox + await click(getComboboxButton()) + assertComboboxList({ state: ComboboxState.Visible }) + assertActiveElement(getComboboxInput()) + + let options = getComboboxOptions() + + // We should not be able to focus the first option + await focus(options[1]) + assertNoActiveComboboxOption() + }) + ) +}) diff --git a/packages/@headlessui-vue/src/components/combobox/combobox.ts b/packages/@headlessui-vue/src/components/combobox/combobox.ts new file mode 100644 index 0000000000..d8c9321e2e --- /dev/null +++ b/packages/@headlessui-vue/src/components/combobox/combobox.ts @@ -0,0 +1,666 @@ +import { + defineComponent, + ref, + provide, + inject, + onMounted, + onUnmounted, + computed, + nextTick, + InjectionKey, + Ref, + ComputedRef, + watchEffect, + toRaw, + watch, + PropType, +} from 'vue' + +import { Features, render, omit } from '../../utils/render' +import { useId } from '../../hooks/use-id' +import { Keys } from '../../keyboard' +import { calculateActiveIndex, Focus } from '../../utils/calculate-active-index' +import { dom } from '../../utils/dom' +import { useWindowEvent } from '../../hooks/use-window-event' +import { useOpenClosed, State, useOpenClosedProvider } from '../../internal/open-closed' +import { match } from '../../utils/match' +import { useResolveButtonType } from '../../hooks/use-resolve-button-type' + +enum ComboboxStates { + Open, + Closed, +} + +type ComboboxOptionDataRef = Ref<{ disabled: boolean; value: unknown }> +type StateDefinition = { + // State + ComboboxState: Ref + value: ComputedRef + orientation: Ref<'vertical' | 'horizontal'> + + labelRef: Ref + inputRef: Ref + buttonRef: Ref + optionsRef: Ref + inputPropsRef: Ref<{ displayValue?: (item: unknown) => string }> + + disabled: Ref + options: Ref<{ id: string; dataRef: ComboboxOptionDataRef }[]> + activeOptionIndex: Ref + + // State mutators + closeCombobox(): void + openCombobox(): void + goToOption(focus: Focus, id?: string): void + selectOption(id: string): void + selectActiveOption(): void + registerOption(id: string, dataRef: ComboboxOptionDataRef): void + unregisterOption(id: string): void + select(value: unknown): void +} + +let ComboboxContext = Symbol('ComboboxContext') as InjectionKey + +function useComboboxContext(component: string) { + let context = inject(ComboboxContext, null) + + if (context === null) { + let err = new Error(`<${component} /> is missing a parent component.`) + if (Error.captureStackTrace) Error.captureStackTrace(err, useComboboxContext) + throw err + } + + return context +} + +// --- + +export let Combobox = defineComponent({ + name: 'Combobox', + emits: { 'update:modelValue': (_value: any) => true }, + props: { + as: { type: [Object, String], default: 'template' }, + disabled: { type: [Boolean], default: false }, + horizontal: { type: [Boolean], default: false }, + modelValue: { type: [Object, String, Number, Boolean] }, + }, + setup(props, { slots, attrs, emit }) { + let ComboboxState = ref(ComboboxStates.Closed) + let labelRef = ref(null) + let inputRef = ref(null) as StateDefinition['inputRef'] + let buttonRef = ref(null) as StateDefinition['buttonRef'] + let optionsRef = ref( + null + ) as StateDefinition['optionsRef'] + let options = ref([]) + let activeOptionIndex = ref(null) + + let value = computed(() => props.modelValue) + + let api = { + ComboboxState, + value, + orientation: computed(() => (props.horizontal ? 'horizontal' : 'vertical')), + inputRef, + labelRef, + buttonRef, + optionsRef, + disabled: computed(() => props.disabled), + options, + activeOptionIndex, + inputPropsRef: ref<{ displayValue?: (item: unknown) => string }>({ displayValue: undefined }), + closeCombobox() { + if (props.disabled) return + if (ComboboxState.value === ComboboxStates.Closed) return + ComboboxState.value = ComboboxStates.Closed + activeOptionIndex.value = null + }, + openCombobox() { + if (props.disabled) return + if (ComboboxState.value === ComboboxStates.Open) return + ComboboxState.value = ComboboxStates.Open + }, + goToOption(focus: Focus, id?: string) { + if (props.disabled) return + if (ComboboxState.value === ComboboxStates.Closed) return + + let nextActiveOptionIndex = calculateActiveIndex( + focus === Focus.Specific + ? { focus: Focus.Specific, id: id! } + : { focus: focus as Exclude }, + { + resolveItems: () => options.value, + resolveActiveIndex: () => activeOptionIndex.value, + resolveId: (option) => option.id, + resolveDisabled: (option) => option.dataRef.disabled, + } + ) + + if (activeOptionIndex.value === nextActiveOptionIndex) return + activeOptionIndex.value = nextActiveOptionIndex + }, + syncInputValue() { + let value = api.value.value + if (!dom(api.inputRef)) return + if (value === undefined) return + let displayValue = api.inputPropsRef.value.displayValue + + if (typeof displayValue === 'function') { + api.inputRef!.value!.value = displayValue(value) + } else if (typeof value === 'string') { + api.inputRef!.value!.value = value + } + }, + selectOption(id: string) { + let option = options.value.find((item) => item.id === id) + if (!option) return + + let { dataRef } = option + emit('update:modelValue', dataRef.value) + api.syncInputValue() + }, + selectActiveOption() { + if (activeOptionIndex.value === null) return + + let { dataRef } = options.value[activeOptionIndex.value] + emit('update:modelValue', dataRef.value) + api.syncInputValue() + }, + registerOption(id: string, dataRef: ComboboxOptionDataRef) { + let currentActiveOption = + activeOptionIndex.value !== null ? options.value[activeOptionIndex.value] : null + let orderMap = Array.from( + optionsRef.value?.querySelectorAll('[id^="headlessui-combobox-option-"]') ?? [] + ).reduce( + (lookup, element, index) => Object.assign(lookup, { [element.id]: index }), + {} + ) as Record + + // @ts-expect-error The expected type comes from property 'dataRef' which is declared here on type '{ id: string; dataRef: { textValue: string; disabled: boolean; }; }' + options.value = [...options.value, { id, dataRef }].sort( + (a, z) => orderMap[a.id] - orderMap[z.id] + ) + + // If we inserted an option before the current active option then the + // active option index would be wrong. To fix this, we will re-lookup + // the correct index. + activeOptionIndex.value = (() => { + if (currentActiveOption === null) return null + return options.value.indexOf(currentActiveOption) + })() + }, + unregisterOption(id: string) { + let nextOptions = options.value.slice() + let currentActiveOption = + activeOptionIndex.value !== null ? nextOptions[activeOptionIndex.value] : null + let idx = nextOptions.findIndex((a) => a.id === id) + if (idx !== -1) nextOptions.splice(idx, 1) + options.value = nextOptions + activeOptionIndex.value = (() => { + if (idx === activeOptionIndex.value) return null + if (currentActiveOption === null) return null + + // If we removed the option before the actual active index, then it would be out of sync. To + // fix this, we will find the correct (new) index position. + return nextOptions.indexOf(currentActiveOption) + })() + }, + } + + useWindowEvent('mousedown', (event) => { + let target = event.target as HTMLElement + let active = document.activeElement + + if (ComboboxState.value !== ComboboxStates.Open) return + + if (dom(inputRef)?.contains(target)) return + if (dom(buttonRef)?.contains(target)) return + if (dom(optionsRef)?.contains(target)) return + + api.closeCombobox() + + if (active !== document.body && active?.contains(target)) return // Keep focus on newly clicked/focused element + if (!event.defaultPrevented) dom(inputRef)?.focus({ preventScroll: true }) + }) + + watchEffect(() => { + api.syncInputValue() + }) + + // @ts-expect-error Types of property 'dataRef' are incompatible. + provide(ComboboxContext, api) + useOpenClosedProvider( + computed(() => + match(ComboboxState.value, { + [ComboboxStates.Open]: State.Open, + [ComboboxStates.Closed]: State.Closed, + }) + ) + ) + + return () => { + let slot = { open: ComboboxState.value === ComboboxStates.Open, disabled: props.disabled } + return render({ + props: omit(props, ['modelValue', 'onUpdate:modelValue', 'disabled', 'horizontal']), + slot, + slots, + attrs, + name: 'Combobox', + }) + } + }, +}) + +// --- + +export let ComboboxLabel = defineComponent({ + name: 'ComboboxLabel', + props: { as: { type: [Object, String], default: 'label' } }, + setup(props, { attrs, slots }) { + let api = useComboboxContext('ComboboxLabel') + let id = `headlessui-combobox-label-${useId()}` + + function handleClick() { + dom(api.inputRef)?.focus({ preventScroll: true }) + } + + return () => { + let slot = { + open: api.ComboboxState.value === ComboboxStates.Open, + disabled: api.disabled.value, + } + + let propsWeControl = { id, ref: api.labelRef, onClick: handleClick } + + return render({ + props: { ...props, ...propsWeControl }, + slot, + attrs, + slots, + name: 'ComboboxLabel', + }) + } + }, +}) + +// --- + +export let ComboboxButton = defineComponent({ + name: 'ComboboxButton', + props: { + as: { type: [Object, String], default: 'button' }, + }, + setup(props, { attrs, slots }) { + let api = useComboboxContext('ComboboxButton') + let id = `headlessui-combobox-button-${useId()}` + + function handleClick(event: MouseEvent) { + if (api.disabled.value) return + if (api.ComboboxState.value === ComboboxStates.Open) { + api.closeCombobox() + } else { + event.preventDefault() + api.openCombobox() + } + + nextTick(() => dom(api.inputRef)?.focus({ preventScroll: true })) + } + + function handleKeydown(event: KeyboardEvent) { + switch (event.key) { + // Ref: https://www.w3.org/TR/wai-aria-practices-1.2/#keyboard-interaction-12 + + case match(api.orientation.value, { + vertical: Keys.ArrowDown, + horizontal: Keys.ArrowRight, + }): + event.preventDefault() + event.stopPropagation() + if (api.ComboboxState.value === ComboboxStates.Closed) { + api.openCombobox() + // TODO: We can't do this outside next frame because the options aren't rendered yet + // But doing this in next frame results in a flicker because the dom mutations are async here + // Basically: + // Sync -> no option list yet + // Next frame -> option list already rendered with selection -> dispatch -> next frame -> now we have the focus on the right element + + // TODO: The spec here is underspecified. There's mention of skipping to the next item when autocomplete has suggested something but nothing regarding a non-autocomplete selection/value + nextTick(() => { + if (!api.value.value) { + api.goToOption(Focus.First) + } + }) + } + nextTick(() => api.inputRef.value?.focus({ preventScroll: true })) + return + + case match(api.orientation.value, { vertical: Keys.ArrowUp, horizontal: Keys.ArrowLeft }): + event.preventDefault() + event.stopPropagation() + if (api.ComboboxState.value === ComboboxStates.Closed) { + api.openCombobox() + nextTick(() => { + if (!api.value.value) { + api.goToOption(Focus.Last) + } + }) + } + nextTick(() => api.inputRef.value?.focus({ preventScroll: true })) + return + + case Keys.Escape: + event.preventDefault() + event.stopPropagation() + api.closeCombobox() + nextTick(() => api.inputRef.value?.focus({ preventScroll: true })) + return + } + } + + let type = useResolveButtonType( + computed(() => ({ as: props.as, type: attrs.type })), + api.buttonRef + ) + + return () => { + let slot = { + open: api.ComboboxState.value === ComboboxStates.Open, + disabled: api.disabled.value, + } + let propsWeControl = { + ref: api.buttonRef, + id, + type: type.value, + tabindex: '-1', + 'aria-haspopup': true, + 'aria-controls': dom(api.optionsRef)?.id, + 'aria-expanded': api.disabled.value + ? undefined + : api.ComboboxState.value === ComboboxStates.Open, + 'aria-labelledby': api.labelRef.value ? [dom(api.labelRef)?.id, id].join(' ') : undefined, + disabled: api.disabled.value === true ? true : undefined, + onKeydown: handleKeydown, + onClick: handleClick, + } + + return render({ + props: { ...props, ...propsWeControl }, + slot, + attrs, + slots, + name: 'ComboboxButton', + }) + } + }, +}) + +// --- + +export let ComboboxInput = defineComponent({ + name: 'ComboboxInput', + props: { + as: { type: [Object, String], default: 'input' }, + static: { type: Boolean, default: false }, + unmount: { type: Boolean, default: true }, + displayValue: { type: Function as PropType<(item: unknown) => string> }, + }, + emits: { + change: (_value: Event & { target: HTMLInputElement }) => true, + }, + setup(props, { emit, attrs, slots }) { + let api = useComboboxContext('ComboboxInput') + let id = `headlessui-combobox-input-${useId()}` + api.inputPropsRef = computed(() => props) + + function handleKeyDown(event: KeyboardEvent) { + switch (event.key) { + // Ref: https://www.w3.org/TR/wai-aria-practices-1.2/#keyboard-interaction-12 + + case Keys.Enter: + event.preventDefault() + event.stopPropagation() + + api.selectActiveOption() + api.closeCombobox() + break + + case match(api.orientation.value, { + vertical: Keys.ArrowDown, + horizontal: Keys.ArrowRight, + }): + event.preventDefault() + event.stopPropagation() + return match(api.ComboboxState.value, { + [ComboboxStates.Open]: () => api.goToOption(Focus.Next), + [ComboboxStates.Closed]: () => { + api.openCombobox() + nextTick(() => { + if (!api.value.value) { + api.goToOption(Focus.First) + } + }) + }, + }) + + case match(api.orientation.value, { vertical: Keys.ArrowUp, horizontal: Keys.ArrowLeft }): + event.preventDefault() + event.stopPropagation() + return match(api.ComboboxState.value, { + [ComboboxStates.Open]: () => api.goToOption(Focus.Previous), + [ComboboxStates.Closed]: () => { + api.openCombobox() + nextTick(() => { + if (!api.value.value) { + api.goToOption(Focus.Last) + } + }) + }, + }) + + case Keys.Home: + case Keys.PageUp: + event.preventDefault() + event.stopPropagation() + return api.goToOption(Focus.First) + + case Keys.End: + case Keys.PageDown: + event.preventDefault() + event.stopPropagation() + return api.goToOption(Focus.Last) + + case Keys.Escape: + event.preventDefault() + event.stopPropagation() + api.closeCombobox() + break + + case Keys.Tab: + api.selectActiveOption() + api.closeCombobox() + break + } + } + + function handleChange(event: Event & { target: HTMLInputElement }) { + api.openCombobox() + emit('change', event) + } + + return () => { + let slot = { open: api.ComboboxState.value === ComboboxStates.Open } + let propsWeControl = { + 'aria-activedescendant': + api.activeOptionIndex.value === null + ? undefined + : api.options.value[api.activeOptionIndex.value]?.id, + 'aria-labelledby': dom(api.labelRef)?.id ?? dom(api.buttonRef)?.id, + 'aria-orientation': api.orientation.value, + id, + onKeydown: handleKeyDown, + onChange: handleChange, + role: 'combobox', + tabIndex: 0, + ref: api.inputRef, + } + let passThroughProps = props + + return render({ + props: { ...passThroughProps, ...propsWeControl }, + slot, + attrs, + slots, + features: Features.RenderStrategy | Features.Static, + name: 'ComboboxInput', + }) + } + }, +}) + +// --- + +export let ComboboxOptions = defineComponent({ + name: 'ComboboxOptions', + props: { + as: { type: [Object, String], default: 'ul' }, + static: { type: Boolean, default: false }, + unmount: { type: Boolean, default: true }, + }, + setup(props, { attrs, slots }) { + let api = useComboboxContext('ComboboxOptions') + let id = `headlessui-combobox-options-${useId()}` + + let usesOpenClosedState = useOpenClosed() + let visible = computed(() => { + if (usesOpenClosedState !== null) { + return usesOpenClosedState.value === State.Open + } + + return api.ComboboxState.value === ComboboxStates.Open + }) + + return () => { + let slot = { open: api.ComboboxState.value === ComboboxStates.Open } + let propsWeControl = { + 'aria-activedescendant': + api.activeOptionIndex.value === null + ? undefined + : api.options.value[api.activeOptionIndex.value]?.id, + 'aria-labelledby': dom(api.labelRef)?.id ?? dom(api.buttonRef)?.id, + 'aria-orientation': api.orientation.value, + id, + ref: api.optionsRef, + role: 'listbox', + } + let passThroughProps = props + + return render({ + props: { ...passThroughProps, ...propsWeControl }, + slot, + attrs, + slots, + features: Features.RenderStrategy | Features.Static, + visible: visible.value, + name: 'ComboboxOptions', + }) + } + }, +}) + +export let ComboboxOption = defineComponent({ + name: 'ComboboxOption', + props: { + as: { type: [Object, String], default: 'li' }, + value: { type: [Object, String, Number, Boolean] }, + disabled: { type: Boolean, default: false }, + }, + setup(props, { slots, attrs }) { + let api = useComboboxContext('ComboboxOption') + let id = `headlessui-combobox-option-${useId()}` + + let active = computed(() => { + return api.activeOptionIndex.value !== null + ? api.options.value[api.activeOptionIndex.value].id === id + : false + }) + + let selected = computed(() => toRaw(api.value.value) === toRaw(props.value)) + + let dataRef = computed(() => ({ + disabled: props.disabled, + value: props.value, + })) + + onMounted(() => api.registerOption(id, dataRef)) + onUnmounted(() => api.unregisterOption(id)) + + onMounted(() => { + watch( + [api.ComboboxState, selected], + () => { + if (api.ComboboxState.value !== ComboboxStates.Open) return + if (!selected.value) return + api.goToOption(Focus.Specific, id) + }, + { immediate: true } + ) + }) + + watchEffect(() => { + if (api.ComboboxState.value !== ComboboxStates.Open) return + if (!active.value) return + nextTick(() => document.getElementById(id)?.scrollIntoView?.({ block: 'nearest' })) + }) + + function handleClick(event: MouseEvent) { + if (props.disabled) return event.preventDefault() + api.selectOption(id) + api.closeCombobox() + nextTick(() => dom(api.inputRef)?.focus({ preventScroll: true })) + } + + function handleFocus() { + if (props.disabled) return api.goToOption(Focus.Nothing) + api.goToOption(Focus.Specific, id) + } + + function handleMove() { + if (props.disabled) return + if (active.value) return + api.goToOption(Focus.Specific, id) + } + + function handleLeave() { + if (props.disabled) return + if (!active.value) return + api.goToOption(Focus.Nothing) + } + + return () => { + let { disabled } = props + let slot = { active: active.value, selected: selected.value, disabled } + let propsWeControl = { + id, + role: 'option', + tabIndex: disabled === true ? undefined : -1, + 'aria-disabled': disabled === true ? true : undefined, + 'aria-selected': selected.value === true ? selected.value : undefined, + disabled: undefined, // Never forward the `disabled` prop + onClick: handleClick, + onFocus: handleFocus, + onPointermove: handleMove, + onMousemove: handleMove, + onPointerleave: handleLeave, + onMouseleave: handleLeave, + } + + return render({ + props: { ...props, ...propsWeControl }, + slot, + attrs, + slots, + name: 'ComboboxOption', + }) + } + }, +}) diff --git a/packages/@headlessui-vue/src/components/description/description.test.ts b/packages/@headlessui-vue/src/components/description/description.test.ts index 2a5ba68640..fdedf821fd 100644 --- a/packages/@headlessui-vue/src/components/description/description.test.ts +++ b/packages/@headlessui-vue/src/components/description/description.test.ts @@ -8,7 +8,8 @@ import { html } from '../../test-utils/html' import { click } from '../../test-utils/interactions' import { getByText } from '../../test-utils/accessibility-assertions' -function format(input: Element | string) { +function format(input: Element | null | string) { + if (input === null) throw new Error('input is null') let contents = (typeof input === 'string' ? input : (input as HTMLElement).outerHTML).trim() return prettier.format(contents, { parser: 'babel' }) } @@ -22,59 +23,45 @@ beforeAll(() => { afterAll(() => jest.restoreAllMocks()) -function renderTemplate(input: string | Partial[0]>) { - let defaultComponents = { Description } - - if (typeof input === 'string') { - return render(defineComponent({ template: input, components: defaultComponents })) - } - - return render( - defineComponent( - Object.assign({}, input, { - components: { ...defaultComponents, ...input.components }, - }) as Parameters[0] - ) - ) -} - it('should be possible to use useDescriptions without using a Description', async () => { - let { container } = renderTemplate({ - render() { - return h('div', [h('div', { 'aria-describedby': this.describedby }, ['No description'])]) - }, - setup() { - let describedby = useDescriptions() - return { describedby } - }, - }) + let { container } = render( + defineComponent({ + components: { Description }, + setup() { + let describedby = useDescriptions() + + return () => + h('div', [h('div', { 'aria-describedby': describedby.value }, ['No description'])]) + }, + }) + ) expect(format(container.firstElementChild)).toEqual( format(html`
-
- No description -
+
No description
`) ) }) it('should be possible to use useDescriptions and a single Description, and have them linked', async () => { - let { container } = renderTemplate({ - render() { - return h('div', [ - h('div', { 'aria-describedby': this.describedby }, [ - h(Description, () => 'I am a description'), - h('span', 'Contents'), - ]), - ]) - }, - setup() { - let describedby = useDescriptions() - return { describedby } - }, - }) + let { container } = render( + defineComponent({ + components: { Description }, + setup() { + let describedby = useDescriptions() + + return () => + h('div', [ + h('div', { 'aria-describedby': describedby.value }, [ + h(Description, () => 'I am a description'), + h('span', 'Contents'), + ]), + ]) + }, + }) + ) await new Promise(nextTick) @@ -82,12 +69,8 @@ it('should be possible to use useDescriptions and a single Description, and have format(html`
-

- I am a description -

- - Contents - +

I am a description

+ Contents
`) @@ -95,21 +78,23 @@ it('should be possible to use useDescriptions and a single Description, and have }) it('should be possible to use useDescriptions and multiple Description components, and have them linked', async () => { - let { container } = renderTemplate({ - render() { - return h('div', [ - h('div', { 'aria-describedby': this.describedby }, [ - h(Description, () => 'I am a description'), - h('span', 'Contents'), - h(Description, () => 'I am also a description'), - ]), - ]) - }, - setup() { - let describedby = useDescriptions() - return { describedby } - }, - }) + let { container } = render( + defineComponent({ + components: { Description }, + setup() { + let describedby = useDescriptions() + + return () => + h('div', [ + h('div', { 'aria-describedby': describedby.value }, [ + h(Description, () => 'I am a description'), + h('span', 'Contents'), + h(Description, () => 'I am also a description'), + ]), + ]) + }, + }) + ) await new Promise(nextTick) @@ -117,15 +102,9 @@ it('should be possible to use useDescriptions and multiple Description component format(html`
-

- I am a description -

- - Contents - -

- I am also a description -

+

I am a description

+ Contents +

I am also a description

`) @@ -133,21 +112,24 @@ it('should be possible to use useDescriptions and multiple Description component }) it('should be possible to update a prop from the parent and it should reflect in the Description component', async () => { - let { container } = renderTemplate({ - render() { - return h('div', [ - h('div', { 'aria-describedby': this.describedby }, [ - h(Description, () => 'I am a description'), - h('button', { onClick: () => this.count++ }, '+1'), - ]), - ]) - }, - setup() { - let count = ref(0) - let describedby = useDescriptions({ props: { 'data-count': count } }) - return { count, describedby } - }, - }) + let { container } = render( + defineComponent({ + components: { Description }, + setup() { + let count = ref(0) + let describedby = useDescriptions({ props: { 'data-count': count } }) + + return () => { + return h('div', [ + h('div', { 'aria-describedby': describedby.value }, [ + h(Description, () => 'I am a description'), + h('button', { onClick: () => count.value++ }, '+1'), + ]), + ]) + } + }, + }) + ) await new Promise(nextTick) @@ -155,9 +137,7 @@ it('should be possible to update a prop from the parent and it should reflect in format(html`
-

- I am a description -

+

I am a description

@@ -170,9 +150,7 @@ it('should be possible to update a prop from the parent and it should reflect in format(html`
-

- I am a description -

+

I am a description

diff --git a/packages/@headlessui-vue/src/components/description/description.ts b/packages/@headlessui-vue/src/components/description/description.ts index 80f8ac9651..6ae3423979 100644 --- a/packages/@headlessui-vue/src/components/description/description.ts +++ b/packages/@headlessui-vue/src/components/description/description.ts @@ -70,31 +70,30 @@ export let Description = defineComponent({ props: { as: { type: [Object, String], default: 'p' }, }, - render() { - let { name = 'Description', slot = ref({}), props = {} } = this.context - let passThroughProps = this.$props - let propsWeControl = { - ...Object.entries(props).reduce( - (acc, [key, value]) => Object.assign(acc, { [key]: unref(value) }), - {} - ), - id: this.id, - } - - return render({ - props: { ...passThroughProps, ...propsWeControl }, - slot: slot.value, - attrs: this.$attrs, - slots: this.$slots, - name, - }) - }, - setup() { + setup(myProps, { attrs, slots }) { let context = useDescriptionContext() let id = `headlessui-description-${useId()}` onMounted(() => onUnmounted(context.register(id))) - return { id, context } + return () => { + let { name = 'Description', slot = ref({}), props = {} } = context + let passThroughProps = myProps + let propsWeControl = { + ...Object.entries(props).reduce( + (acc, [key, value]) => Object.assign(acc, { [key]: unref(value) }), + {} + ), + id, + } + + return render({ + props: { ...passThroughProps, ...propsWeControl }, + slot: slot.value, + attrs, + slots, + name, + }) + } }, }) diff --git a/packages/@headlessui-vue/src/components/dialog/dialog.test.ts b/packages/@headlessui-vue/src/components/dialog/dialog.test.ts index 206c4328cf..2eedd73252 100644 --- a/packages/@headlessui-vue/src/components/dialog/dialog.test.ts +++ b/packages/@headlessui-vue/src/components/dialog/dialog.test.ts @@ -1,4 +1,11 @@ -import { defineComponent, ref, nextTick, h } from 'vue' +import { + defineComponent, + ref, + nextTick, + h, + ComponentOptionsWithoutProps, + ConcreteComponent, +} from 'vue' import { render } from '../../test-utils/vue-testing-library' import { Dialog, DialogOverlay, DialogTitle, DialogDescription } from './dialog' @@ -30,9 +37,7 @@ afterAll(() => jest.restoreAllMocks()) let TabSentinel = defineComponent({ name: 'TabSentinel', - template: html` -
- `, + template: html`
`, }) jest.mock('../../hooks/use-id') @@ -44,7 +49,7 @@ beforeAll(() => { afterAll(() => jest.restoreAllMocks()) -function renderTemplate(input: string | Partial[0]>) { +function renderTemplate(input: string | ComponentOptionsWithoutProps) { let defaultComponents = { Dialog, DialogOverlay, DialogTitle, DialogDescription, TabSentinel } if (typeof input === 'string') { @@ -933,61 +938,50 @@ describe('Mouse interactions', () => { }) describe('Nesting', () => { - let Nested = defineComponent({ + let Nested: ConcreteComponent = defineComponent({ components: { Dialog, DialogOverlay }, emits: ['close'], props: ['level'], - render() { - let level = this.$props.level ?? 1 - return h(Dialog, { open: true, onClose: this.onClose }, () => [ - h(DialogOverlay), - h('div', [ - h('p', `Level: ${level}`), - h( - 'button', - { - onClick: () => { - this.showChild = true + setup(props, { emit }) { + let showChild = ref(false) + function onClose() { + emit('close', false) + } + + return () => { + let level = props.level ?? 1 + return h(Dialog, { open: true, onClose: onClose }, () => [ + h(DialogOverlay), + h('div', [ + h('p', `Level: ${level}`), + h( + 'button', + { + onClick: () => (showChild.value = true), }, - }, - `Open ${level + 1} a` - ), - h( - 'button', - { - onClick: () => { - this.showChild = true + `Open ${level + 1} a` + ), + h( + 'button', + { + onClick: () => (showChild.value = true), }, - }, - `Open ${level + 1} b` - ), - h( - 'button', - { - onClick: () => { - this.showChild = true + `Open ${level + 1} b` + ), + h( + 'button', + { + onClick: () => (showChild.value = true), }, - }, - `Open ${level + 1} c` - ), - ]), - this.showChild && - h(Nested, { - onClose: () => { - this.showChild = false - }, - level: level + 1, - }), - ]) - }, - setup(_props, { emit }) { - let showChild = ref(false) - - return { - showChild, - onClose() { - emit('close', false) - }, + `Open ${level + 1} c` + ), + ]), + showChild.value && + h(Nested, { + onClose: () => (showChild.value = false), + level: level + 1, + }), + ]) } }, }) diff --git a/packages/@headlessui-vue/src/components/dialog/dialog.ts b/packages/@headlessui-vue/src/components/dialog/dialog.ts index 31d7e8808b..057e78aa54 100644 --- a/packages/@headlessui-vue/src/components/dialog/dialog.ts +++ b/packages/@headlessui-vue/src/components/dialog/dialog.ts @@ -75,42 +75,7 @@ export let Dialog = defineComponent({ initialFocus: { type: Object as PropType, default: null }, }, emits: { close: (_close: boolean) => true }, - render() { - let propsWeControl = { - // Manually passthrough the attributes, because Vue can't automatically pass - // it to the underlying div because of all the wrapper components below. - ...this.$attrs, - ref: 'el', - id: this.id, - role: 'dialog', - 'aria-modal': this.dialogState === DialogStates.Open ? true : undefined, - 'aria-labelledby': this.titleId, - 'aria-describedby': this.describedby, - onClick: this.handleClick, - } - let { open: _, initialFocus, ...passThroughProps } = this.$props - - let slot = { open: this.dialogState === DialogStates.Open } - - return h(ForcePortalRoot, { force: true }, () => - h(Portal, () => - h(PortalGroup, { target: this.dialogRef }, () => - h(ForcePortalRoot, { force: false }, () => - render({ - props: { ...passThroughProps, ...propsWeControl }, - slot, - attrs: this.$attrs, - slots: this.$slots, - visible: this.visible, - features: Features.RenderStrategy | Features.Static, - name: 'Dialog', - }) - ) - ) - ) - ) - }, - setup(props, { emit }) { + setup(props, { emit, attrs, slots }) { let containers = ref>(new Set()) let usesOpenClosedState = useOpenClosed() @@ -193,7 +158,7 @@ export let Dialog = defineComponent({ provide(DialogContext, api) // Handle outside click - useWindowEvent('mousedown', event => { + useWindowEvent('mousedown', (event) => { let target = event.target as HTMLElement if (dialogState.value !== DialogStates.Open) return @@ -205,7 +170,7 @@ export let Dialog = defineComponent({ }) // Handle `Escape` to close - useWindowEvent('keydown', event => { + useWindowEvent('keydown', (event) => { if (event.key !== Keys.Escape) return if (dialogState.value !== DialogStates.Open) return if (containers.value.size > 1) return // 1 is myself, otherwise other elements in the Stack @@ -215,7 +180,7 @@ export let Dialog = defineComponent({ }) // Scroll lock - watchEffect(onInvalidate => { + watchEffect((onInvalidate) => { if (dialogState.value !== DialogStates.Open) return let overflow = document.documentElement.style.overflow @@ -233,12 +198,12 @@ export let Dialog = defineComponent({ }) // Trigger close when the FocusTrap gets hidden - watchEffect(onInvalidate => { + watchEffect((onInvalidate) => { if (dialogState.value !== DialogStates.Open) return let container = dom(internalDialogRef) if (!container) return - let observer = new IntersectionObserver(entries => { + let observer = new IntersectionObserver((entries) => { for (let entry of entries) { if ( entry.boundingClientRect.x === 0 && @@ -256,19 +221,44 @@ export let Dialog = defineComponent({ onInvalidate(() => observer.disconnect()) }) - return { - id, - el: internalDialogRef, - dialogRef: internalDialogRef, - containers, - dialogState, - titleId, - describedby, - visible, - open, - handleClick(event: MouseEvent) { - event.stopPropagation() - }, + function handleClick(event: MouseEvent) { + event.stopPropagation() + } + + return () => { + let propsWeControl = { + // Manually passthrough the attributes, because Vue can't automatically pass + // it to the underlying div because of all the wrapper components below. + ...attrs, + ref: internalDialogRef, + id, + role: 'dialog', + 'aria-modal': dialogState.value === DialogStates.Open ? true : undefined, + 'aria-labelledby': titleId.value, + 'aria-describedby': describedby.value, + onClick: handleClick, + } + let { open: _, initialFocus, ...passThroughProps } = props + + let slot = { open: dialogState.value === DialogStates.Open } + + return h(ForcePortalRoot, { force: true }, () => + h(Portal, () => + h(PortalGroup, { target: internalDialogRef.value }, () => + h(ForcePortalRoot, { force: false }, () => + render({ + props: { ...passThroughProps, ...propsWeControl }, + slot, + attrs, + slots, + visible: visible.value, + features: Features.RenderStrategy | Features.Static, + name: 'Dialog', + }) + ) + ) + ) + ) } }, }) @@ -280,36 +270,32 @@ export let DialogOverlay = defineComponent({ props: { as: { type: [Object, String], default: 'div' }, }, - render() { - let api = useDialogContext('DialogOverlay') - let propsWeControl = { - ref: 'el', - id: this.id, - 'aria-hidden': true, - onClick: this.handleClick, - } - let passThroughProps = this.$props - - return render({ - props: { ...passThroughProps, ...propsWeControl }, - slot: { open: api.dialogState.value === DialogStates.Open }, - attrs: this.$attrs, - slots: this.$slots, - name: 'DialogOverlay', - }) - }, - setup() { + setup(props, { attrs, slots }) { let api = useDialogContext('DialogOverlay') let id = `headlessui-dialog-overlay-${useId()}` - return { - id, - handleClick(event: MouseEvent) { - if (event.target !== event.currentTarget) return - event.preventDefault() - event.stopPropagation() - api.close() - }, + function handleClick(event: MouseEvent) { + if (event.target !== event.currentTarget) return + event.preventDefault() + event.stopPropagation() + api.close() + } + + return () => { + let propsWeControl = { + id, + 'aria-hidden': true, + onClick: handleClick, + } + let passThroughProps = props + + return render({ + props: { ...passThroughProps, ...propsWeControl }, + slot: { open: api.dialogState.value === DialogStates.Open }, + attrs, + slots, + name: 'DialogOverlay', + }) } }, }) @@ -321,20 +307,7 @@ export let DialogTitle = defineComponent({ props: { as: { type: [Object, String], default: 'h2' }, }, - render() { - let api = useDialogContext('DialogTitle') - let propsWeControl = { id: this.id } - let passThroughProps = this.$props - - return render({ - props: { ...passThroughProps, ...propsWeControl }, - slot: { open: api.dialogState.value === DialogStates.Open }, - attrs: this.$attrs, - slots: this.$slots, - name: 'DialogTitle', - }) - }, - setup() { + setup(props, { attrs, slots }) { let api = useDialogContext('DialogTitle') let id = `headlessui-dialog-title-${useId()}` @@ -343,7 +316,18 @@ export let DialogTitle = defineComponent({ onUnmounted(() => api.setTitleId(null)) }) - return { id } + return () => { + let propsWeControl = { id } + let passThroughProps = props + + return render({ + props: { ...passThroughProps, ...propsWeControl }, + slot: { open: api.dialogState.value === DialogStates.Open }, + attrs, + slots, + name: 'DialogTitle', + }) + } }, }) diff --git a/packages/@headlessui-vue/src/components/disclosure/disclosure.test.ts b/packages/@headlessui-vue/src/components/disclosure/disclosure.test.ts index 415513357b..36cb854405 100644 --- a/packages/@headlessui-vue/src/components/disclosure/disclosure.test.ts +++ b/packages/@headlessui-vue/src/components/disclosure/disclosure.test.ts @@ -1,4 +1,4 @@ -import { defineComponent, nextTick, ref, watch, h } from 'vue' +import { defineComponent, nextTick, ref, watch, h, ComponentOptionsWithoutProps } from 'vue' import { render } from '../../test-utils/vue-testing-library' import { Disclosure, DisclosureButton, DisclosurePanel } from './disclosure' import { suppressConsoleLogs } from '../../test-utils/suppress-console-logs' @@ -19,7 +19,7 @@ jest.mock('../../hooks/use-id') afterAll(() => jest.restoreAllMocks()) -function renderTemplate(input: string | Partial[0]>) { +function renderTemplate(input: string | ComponentOptionsWithoutProps) { let defaultComponents = { Disclosure, DisclosureButton, DisclosurePanel } if (typeof input === 'string') { @@ -297,9 +297,7 @@ describe('Rendering', () => { renderTemplate( html` - - Trigger - + Trigger ` ) @@ -311,9 +309,7 @@ describe('Rendering', () => { renderTemplate( html` - - Trigger - + Trigger ` ) @@ -327,14 +323,12 @@ describe('Rendering', () => { renderTemplate({ template: html` - - Trigger - + Trigger `, setup: () => ({ CustomButton: defineComponent({ - setup: props => () => h('button', { ...props }), + setup: (props) => () => h('button', { ...props }), }), }), }) @@ -349,9 +343,7 @@ describe('Rendering', () => { renderTemplate( html` - - Trigger - + Trigger ` ) @@ -365,14 +357,12 @@ describe('Rendering', () => { renderTemplate({ template: html` - - Trigger - + Trigger `, setup: () => ({ CustomButton: defineComponent({ - setup: props => () => h('div', props), + setup: (props) => () => h('div', props), }), }), }) diff --git a/packages/@headlessui-vue/src/components/disclosure/disclosure.ts b/packages/@headlessui-vue/src/components/disclosure/disclosure.ts index 23fe0a3f18..2f6c5fec18 100644 --- a/packages/@headlessui-vue/src/components/disclosure/disclosure.ts +++ b/packages/@headlessui-vue/src/components/disclosure/disclosure.ts @@ -133,40 +133,7 @@ export let DisclosureButton = defineComponent({ as: { type: [Object, String], default: 'button' }, disabled: { type: [Boolean], default: false }, }, - render() { - let api = useDisclosureContext('DisclosureButton') - - let slot = { open: api.disclosureState.value === DisclosureStates.Open } - let propsWeControl = this.isWithinPanel - ? { - ref: 'el', - type: this.type, - onClick: this.handleClick, - onKeydown: this.handleKeyDown, - } - : { - id: this.id, - ref: 'el', - type: this.type, - 'aria-expanded': this.$props.disabled - ? undefined - : api.disclosureState.value === DisclosureStates.Open, - 'aria-controls': dom(api.panel) ? api.panelId : undefined, - disabled: this.$props.disabled ? true : undefined, - onClick: this.handleClick, - onKeydown: this.handleKeyDown, - onKeyup: this.handleKeyUp, - } - - return render({ - props: { ...this.$props, ...propsWeControl }, - slot, - attrs: this.$attrs, - slots: this.$slots, - name: 'DisclosureButton', - }) - }, - setup(props, { attrs }) { + setup(props, { attrs, slots }) { let api = useDisclosureContext('DisclosureButton') let panelContext = useDisclosurePanelContext() @@ -180,58 +147,86 @@ export let DisclosureButton = defineComponent({ }) } - return { - isWithinPanel, - id: api.buttonId, - el: elementRef, - type: useResolveButtonType( - computed(() => ({ as: props.as, type: attrs.type })), - elementRef - ), - handleClick() { - if (props.disabled) return - - if (isWithinPanel) { - api.toggleDisclosure() - dom(api.button)?.focus() - } else { - api.toggleDisclosure() - } - }, - handleKeyDown(event: KeyboardEvent) { - if (props.disabled) return - - if (isWithinPanel) { - switch (event.key) { - case Keys.Space: - case Keys.Enter: - event.preventDefault() - event.stopPropagation() - api.toggleDisclosure() - dom(api.button)?.focus() - break - } - } else { - switch (event.key) { - case Keys.Space: - case Keys.Enter: - event.preventDefault() - event.stopPropagation() - api.toggleDisclosure() - break - } + let type = useResolveButtonType( + computed(() => ({ as: props.as, type: attrs.type })), + elementRef + ) + + function handleClick() { + if (props.disabled) return + + if (isWithinPanel) { + api.toggleDisclosure() + dom(api.button)?.focus() + } else { + api.toggleDisclosure() + } + } + function handleKeyDown(event: KeyboardEvent) { + if (props.disabled) return + + if (isWithinPanel) { + switch (event.key) { + case Keys.Space: + case Keys.Enter: + event.preventDefault() + event.stopPropagation() + api.toggleDisclosure() + dom(api.button)?.focus() + break } - }, - handleKeyUp(event: KeyboardEvent) { + } else { switch (event.key) { case Keys.Space: - // Required for firefox, event.preventDefault() in handleKeyDown for - // the Space key doesn't cancel the handleKeyUp, which in turn - // triggers a *click*. + case Keys.Enter: event.preventDefault() + event.stopPropagation() + api.toggleDisclosure() break } - }, + } + } + function handleKeyUp(event: KeyboardEvent) { + switch (event.key) { + case Keys.Space: + // Required for firefox, event.preventDefault() in handleKeyDown for + // the Space key doesn't cancel the handleKeyUp, which in turn + // triggers a *click*. + event.preventDefault() + break + } + } + + return () => { + let slot = { open: api.disclosureState.value === DisclosureStates.Open } + let propsWeControl = isWithinPanel + ? { + ref: elementRef, + type: type.value, + onClick: handleClick, + onKeydown: handleKeyDown, + } + : { + id: api.buttonId, + ref: elementRef, + type: type.value, + 'aria-expanded': props.disabled + ? undefined + : api.disclosureState.value === DisclosureStates.Open, + 'aria-controls': dom(api.panel) ? api.panelId : undefined, + disabled: props.disabled ? true : undefined, + onClick: handleClick, + onKeydown: handleKeyDown, + onKeyup: handleKeyUp, + } + + return render({ + props: { ...props, ...propsWeControl }, + slot, + attrs, + slots, + name: 'DisclosureButton', + }) } }, }) @@ -245,23 +240,7 @@ export let DisclosurePanel = defineComponent({ static: { type: Boolean, default: false }, unmount: { type: Boolean, default: true }, }, - render() { - let api = useDisclosureContext('DisclosurePanel') - - let slot = { open: api.disclosureState.value === DisclosureStates.Open, close: api.close } - let propsWeControl = { id: this.id, ref: 'el' } - - return render({ - props: { ...this.$props, ...propsWeControl }, - slot, - attrs: this.$attrs, - slots: this.$slots, - features: Features.RenderStrategy | Features.Static, - visible: this.visible, - name: 'DisclosurePanel', - }) - }, - setup() { + setup(props, { attrs, slots }) { let api = useDisclosureContext('DisclosurePanel') provide(DisclosurePanelContext, api.panelId) @@ -275,10 +254,19 @@ export let DisclosurePanel = defineComponent({ return api.disclosureState.value === DisclosureStates.Open }) - return { - id: api.panelId, - el: api.panel, - visible, + return () => { + let slot = { open: api.disclosureState.value === DisclosureStates.Open, close: api.close } + let propsWeControl = { id: api.panelId, ref: api.panel } + + return render({ + props: { ...props, ...propsWeControl }, + slot, + attrs, + slots, + features: Features.RenderStrategy | Features.Static, + visible: visible.value, + name: 'DisclosurePanel', + }) } }, }) diff --git a/packages/@headlessui-vue/src/components/focus-trap/focus-trap.test.ts b/packages/@headlessui-vue/src/components/focus-trap/focus-trap.test.ts index 8243a82ff4..8d6707250f 100644 --- a/packages/@headlessui-vue/src/components/focus-trap/focus-trap.test.ts +++ b/packages/@headlessui-vue/src/components/focus-trap/focus-trap.test.ts @@ -1,4 +1,4 @@ -import { defineComponent, ref, nextTick, onMounted } from 'vue' +import { defineComponent, ref, nextTick, onMounted, ComponentOptionsWithoutProps } from 'vue' import { FocusTrap } from './focus-trap' import { assertActiveElement, getByText } from '../../test-utils/accessibility-assertions' @@ -16,7 +16,7 @@ beforeAll(() => { afterAll(() => jest.restoreAllMocks()) -function renderTemplate(input: string | Partial[0]>) { +function renderTemplate(input: string | ComponentOptionsWithoutProps) { let defaultComponents = { FocusTrap } if (typeof input === 'string') { @@ -41,7 +41,7 @@ it('should focus the first focusable element inside the FocusTrap', async () => ` ) - await new Promise(nextTick) + await new Promise(nextTick) assertActiveElement(getByText('Trigger')) }) @@ -64,7 +64,7 @@ it('should focus the autoFocus element inside the FocusTrap if that exists', asy }, }) - await new Promise(nextTick) + await new Promise(nextTick) assertActiveElement(document.getElementById('b')) }) @@ -84,7 +84,7 @@ it('should focus the initialFocus element inside the FocusTrap if that exists', }, }) - await new Promise(nextTick) + await new Promise(nextTick) assertActiveElement(document.getElementById('c')) }) @@ -104,7 +104,7 @@ it('should focus the initialFocus element inside the FocusTrap even if another e }, }) - await new Promise(nextTick) + await new Promise(nextTick) assertActiveElement(document.getElementById('c')) }) @@ -121,7 +121,7 @@ it('should warn when there is no focusable element inside the FocusTrap', async ` ) - await new Promise(nextTick) + await new Promise(nextTick) expect(spy.mock.calls[0][0]).toBe('There are no focusable elements inside the ') }) @@ -143,7 +143,7 @@ it( `, }) - await new Promise(nextTick) + await new Promise(nextTick) let [a, b, c, d] = Array.from(document.querySelectorAll('input')) @@ -193,14 +193,10 @@ it('should restore the previously focused element, before entering the FocusTrap template: html`
- + - +
`, @@ -214,7 +210,7 @@ it('should restore the previously focused element, before entering the FocusTrap }, }) - await new Promise(nextTick) + await new Promise(nextTick) // The input should have focus by default because of the autoFocus prop assertActiveElement(document.getElementById('item-1')) @@ -247,7 +243,7 @@ it('should be possible to tab to the next focusable element within the focus tra ` ) - await new Promise(nextTick) + await new Promise(nextTick) // Item A should be focused because the FocusTrap will focus the first item assertActiveElement(document.getElementById('item-a')) @@ -302,12 +298,8 @@ it('should skip the initial "hidden" elements within the focus trap', async () =
- - + + @@ -328,9 +320,7 @@ it('should be possible skip "hidden" elements within the focus trap', async () = - + @@ -364,9 +354,7 @@ it('should be possible skip disabled elements within the focus trap', async () = - + diff --git a/packages/@headlessui-vue/src/components/focus-trap/focus-trap.ts b/packages/@headlessui-vue/src/components/focus-trap/focus-trap.ts index 48e9629d71..dd9bc87eb1 100644 --- a/packages/@headlessui-vue/src/components/focus-trap/focus-trap.ts +++ b/packages/@headlessui-vue/src/components/focus-trap/focus-trap.ts @@ -17,20 +17,7 @@ export let FocusTrap = defineComponent({ as: { type: [Object, String], default: 'div' }, initialFocus: { type: Object as PropType, default: null }, }, - render() { - let slot = {} - let propsWeControl = { ref: 'el' } - let { initialFocus, ...passThroughProps } = this.$props - - return render({ - props: { ...passThroughProps, ...propsWeControl }, - slot, - attrs: this.$attrs, - slots: this.$slots, - name: 'FocusTrap', - }) - }, - setup(props) { + setup(props, { attrs, slots }) { let containers = ref(new Set()) let container = ref(null) let enabled = ref(true) @@ -47,6 +34,18 @@ export let FocusTrap = defineComponent({ enabled.value = false }) - return { el: container } + return () => { + let slot = {} + let propsWeControl = { ref: container } + let { initialFocus, ...passThroughProps } = props + + return render({ + props: { ...passThroughProps, ...propsWeControl }, + slot, + attrs, + slots, + name: 'FocusTrap', + }) + } }, }) diff --git a/packages/@headlessui-vue/src/components/label/label.test.ts b/packages/@headlessui-vue/src/components/label/label.test.ts index f2184e9b66..fff816762a 100644 --- a/packages/@headlessui-vue/src/components/label/label.test.ts +++ b/packages/@headlessui-vue/src/components/label/label.test.ts @@ -8,7 +8,8 @@ import { html } from '../../test-utils/html' import { click } from '../../test-utils/interactions' import { getByText } from '../../test-utils/accessibility-assertions' -function format(input: Element | string) { +function format(input: Element | null | string) { + if (input === null) throw new Error('input is null') let contents = (typeof input === 'string' ? input : (input as HTMLElement).outerHTML).trim() return prettier.format(contents, { parser: 'babel' }) } @@ -22,59 +23,44 @@ beforeAll(() => { afterAll(() => jest.restoreAllMocks()) -function renderTemplate(input: string | Partial[0]>) { - let defaultComponents = { Label } - - if (typeof input === 'string') { - return render(defineComponent({ template: input, components: defaultComponents })) - } - - return render( - defineComponent( - Object.assign({}, input, { - components: { ...defaultComponents, ...input.components }, - }) as Parameters[0] - ) - ) -} - it('should be possible to use useLabels without using a Label', async () => { - let { container } = renderTemplate({ - render() { - return h('div', [h('div', { 'aria-labelledby': this.labelledby }, ['No label'])]) - }, - setup() { - let labelledby = useLabels() - return { labelledby } - }, - }) + let { container } = render( + defineComponent({ + components: { Label }, + setup() { + let labelledby = useLabels() + + return () => h('div', [h('div', { 'aria-labelledby': labelledby.value }, ['No label'])]) + }, + }) + ) expect(format(container.firstElementChild)).toEqual( format(html`
-
- No label -
+
No label
`) ) }) it('should be possible to use useLabels and a single Label, and have them linked', async () => { - let { container } = renderTemplate({ - render() { - return h('div', [ - h('div', { 'aria-labelledby': this.labelledby }, [ - h(Label, () => 'I am a label'), - h('span', 'Contents'), - ]), - ]) - }, - setup() { - let labelledby = useLabels() - return { labelledby } - }, - }) + let { container } = render( + defineComponent({ + components: { Label }, + setup() { + let labelledby = useLabels() + + return () => + h('div', [ + h('div', { 'aria-labelledby': labelledby.value }, [ + h(Label, () => 'I am a label'), + h('span', 'Contents'), + ]), + ]) + }, + }) + ) await new Promise(nextTick) @@ -82,12 +68,8 @@ it('should be possible to use useLabels and a single Label, and have them linked format(html`
- - - Contents - + + Contents
`) @@ -95,21 +77,23 @@ it('should be possible to use useLabels and a single Label, and have them linked }) it('should be possible to use useLabels and multiple Label components, and have them linked', async () => { - let { container } = renderTemplate({ - render() { - return h('div', [ - h('div', { 'aria-labelledby': this.labelledby }, [ - h(Label, () => 'I am a label'), - h('span', 'Contents'), - h(Label, () => 'I am also a label'), - ]), - ]) - }, - setup() { - let labelledby = useLabels() - return { labelledby } - }, - }) + let { container } = render( + defineComponent({ + components: { Label }, + setup() { + let labelledby = useLabels() + + return () => + h('div', [ + h('div', { 'aria-labelledby': labelledby.value }, [ + h(Label, () => 'I am a label'), + h('span', 'Contents'), + h(Label, () => 'I am also a label'), + ]), + ]) + }, + }) + ) await new Promise(nextTick) @@ -117,15 +101,9 @@ it('should be possible to use useLabels and multiple Label components, and have format(html`
- - - Contents - - + + Contents +
`) @@ -133,21 +111,23 @@ it('should be possible to use useLabels and multiple Label components, and have }) it('should be possible to update a prop from the parent and it should reflect in the Label component', async () => { - let { container } = renderTemplate({ - render() { - return h('div', [ - h('div', { 'aria-labelledby': this.labelledby }, [ - h(Label, () => 'I am a label'), - h('button', { onClick: () => this.count++ }, '+1'), - ]), - ]) - }, - setup() { - let count = ref(0) - let labelledby = useLabels({ props: { 'data-count': count } }) - return { count, labelledby } - }, - }) + let { container } = render( + defineComponent({ + components: { Label }, + setup() { + let count = ref(0) + let labelledby = useLabels({ props: { 'data-count': count } }) + + return () => + h('div', [ + h('div', { 'aria-labelledby': labelledby.value }, [ + h(Label, () => 'I am a label'), + h('button', { onClick: () => count.value++ }, '+1'), + ]), + ]) + }, + }) + ) await new Promise(nextTick) @@ -155,9 +135,7 @@ it('should be possible to update a prop from the parent and it should reflect in format(html`
- +
@@ -170,9 +148,7 @@ it('should be possible to update a prop from the parent and it should reflect in format(html`
- +
diff --git a/packages/@headlessui-vue/src/components/label/label.ts b/packages/@headlessui-vue/src/components/label/label.ts index 77b9bd730f..f29b99fae6 100644 --- a/packages/@headlessui-vue/src/components/label/label.ts +++ b/packages/@headlessui-vue/src/components/label/label.ts @@ -69,36 +69,35 @@ export let Label = defineComponent({ as: { type: [Object, String], default: 'label' }, passive: { type: [Boolean], default: false }, }, - render() { - let { name = 'Label', slot = {}, props = {} } = this.context - let { passive, ...passThroughProps } = this.$props - let propsWeControl = { - ...Object.entries(props).reduce( - (acc, [key, value]) => Object.assign(acc, { [key]: unref(value) }), - {} - ), - id: this.id, - } - let allProps = { ...passThroughProps, ...propsWeControl } - - // @ts-expect-error props are dynamic via context, some components will - // provide an onClick then we can delete it. - if (passive) delete allProps['onClick'] - - return render({ - props: allProps, - slot, - attrs: this.$attrs, - slots: this.$slots, - name, - }) - }, - setup() { + setup(myProps, { slots, attrs }) { let context = useLabelContext() let id = `headlessui-label-${useId()}` onMounted(() => onUnmounted(context.register(id))) - return { id, context } + return () => { + let { name = 'Label', slot = {}, props = {} } = context + let { passive, ...passThroughProps } = myProps + let propsWeControl = { + ...Object.entries(props).reduce( + (acc, [key, value]) => Object.assign(acc, { [key]: unref(value) }), + {} + ), + id, + } + let allProps = { ...passThroughProps, ...propsWeControl } + + // @ts-expect-error props are dynamic via context, some components will + // provide an onClick then we can delete it. + if (passive) delete allProps['onClick'] + + return render({ + props: allProps, + slot, + attrs, + slots, + name, + }) + } }, }) diff --git a/packages/@headlessui-vue/src/components/listbox/listbox.test.tsx b/packages/@headlessui-vue/src/components/listbox/listbox.test.tsx index c0a437e995..c3cd561fef 100644 --- a/packages/@headlessui-vue/src/components/listbox/listbox.test.tsx +++ b/packages/@headlessui-vue/src/components/listbox/listbox.test.tsx @@ -1,4 +1,12 @@ -import { defineComponent, nextTick, ref, watch, h, reactive } from 'vue' +import { + defineComponent, + nextTick, + ref, + watch, + h, + reactive, + ComponentOptionsWithoutProps, +} from 'vue' import { render } from '../../test-utils/vue-testing-library' import { Listbox, ListboxLabel, ListboxButton, ListboxOptions, ListboxOption } from './listbox' import { suppressConsoleLogs } from '../../test-utils/suppress-console-logs' @@ -48,7 +56,7 @@ beforeAll(() => { afterAll(() => jest.restoreAllMocks()) function nextFrame() { - return new Promise(resolve => { + return new Promise((resolve) => { requestAnimationFrame(() => { requestAnimationFrame(() => { resolve() @@ -57,7 +65,7 @@ function nextFrame() { }) } -function renderTemplate(input: string | Partial[0]>) { +function renderTemplate(input: string | ComponentOptionsWithoutProps) { let defaultComponents = { Listbox, ListboxLabel, ListboxButton, ListboxOptions, ListboxOption } if (typeof input === 'string') { @@ -388,9 +396,7 @@ describe('Rendering', () => { renderTemplate({ template: html` - - Trigger - + Trigger `, setup: () => ({ value: ref(null) }), @@ -405,15 +411,13 @@ describe('Rendering', () => { renderTemplate({ template: html` - - Trigger - + Trigger `, setup: () => ({ value: ref(null), CustomButton: defineComponent({ - setup: props => () => h('button', { ...props }), + setup: (props) => () => h('button', { ...props }), }), }), }) @@ -428,9 +432,7 @@ describe('Rendering', () => { renderTemplate({ template: html` - - Trigger - + Trigger `, setup: () => ({ value: ref(null) }), @@ -445,15 +447,13 @@ describe('Rendering', () => { renderTemplate({ template: html` - - Trigger - + Trigger `, setup: () => ({ value: ref(null), CustomButton: defineComponent({ - setup: props => () => h('div', props), + setup: (props) => () => h('div', props), }), }), }) @@ -647,15 +647,9 @@ describe('Rendering composition', () => { Trigger - - Option A - - - Option B - - - Option C - + Option A + Option B + Option C `, @@ -672,7 +666,7 @@ describe('Rendering composition', () => { await click(getListboxButton()) // Verify options are buttons now - getListboxOptions().forEach(option => assertListboxOption(option, { tag: 'button' })) + getListboxOptions().forEach((option) => assertListboxOption(option, { tag: 'button' })) }) ) }) @@ -704,9 +698,7 @@ describe('Composition', () => { Trigger - - {{JSON.stringify(data)}} - + {{JSON.stringify(data)}} `, @@ -734,9 +726,7 @@ describe('Composition', () => { Trigger - - {{JSON.stringify(data)}} - + {{JSON.stringify(data)}} `, @@ -840,7 +830,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option, { selected: false })) + options.forEach((option) => assertListboxOption(option, { selected: false })) // Verify that the first listbox option is active assertActiveListboxOption(options[0]) @@ -1092,9 +1082,7 @@ describe('Keyboard interactions', () => { Trigger - - Option A - + Option A Option B Option C @@ -1130,12 +1118,8 @@ describe('Keyboard interactions', () => { Trigger - - Option A - - - Option B - + Option A + Option B Option C @@ -1170,15 +1154,9 @@ describe('Keyboard interactions', () => { Trigger - - Option A - - - Option B - - - Option C - + Option A + Option B + Option C `, @@ -1345,7 +1323,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[0]) }) ) @@ -1471,9 +1449,7 @@ describe('Keyboard interactions', () => { Trigger - - Option A - + Option A Option B Option C @@ -1509,12 +1485,8 @@ describe('Keyboard interactions', () => { Trigger - - Option A - - - Option B - + Option A + Option B Option C @@ -1549,15 +1521,9 @@ describe('Keyboard interactions', () => { Trigger - - Option A - - - Option B - - - Option C - + Option A + Option B + Option C `, @@ -1729,7 +1695,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[0]) // Try to tab @@ -1783,7 +1749,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[0]) // Try to Shift+Tab @@ -1839,7 +1805,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) // Verify that the first listbox option is active assertActiveListboxOption(options[0]) @@ -1991,7 +1957,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[0]) // We should be able to go down once @@ -2016,9 +1982,7 @@ describe('Keyboard interactions', () => { Trigger - - Option A - + Option A Option B Option C @@ -2042,7 +2006,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[1]) // We should be able to go down once @@ -2059,12 +2023,8 @@ describe('Keyboard interactions', () => { Trigger - - Option A - - - Option B - + Option A + Option B Option C @@ -2087,7 +2047,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[2]) }) ) @@ -2126,7 +2086,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[0]) // We should be able to go right once @@ -2186,7 +2146,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) // ! ALERT: The LAST option should now be active assertActiveListboxOption(options[2]) @@ -2315,12 +2275,8 @@ describe('Keyboard interactions', () => { Trigger Option A - - Option B - - - Option C - + Option B + Option C `, @@ -2342,7 +2298,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[0]) }) ) @@ -2355,12 +2311,8 @@ describe('Keyboard interactions', () => { Trigger - - Option A - - - Option B - + Option A + Option B Option C @@ -2383,7 +2335,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[2]) // We should not be able to go up (because those are disabled) @@ -2437,7 +2389,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[2]) // We should be able to go down once @@ -2498,7 +2450,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[2]) // We should be able to go left once @@ -2561,12 +2513,8 @@ describe('Keyboard interactions', () => { Option A Option B - - Option C - - - Option D - + Option C + Option D `, @@ -2599,15 +2547,9 @@ describe('Keyboard interactions', () => { Trigger Option A - - Option B - - - Option C - - - Option D - + Option B + Option C + Option D `, @@ -2636,18 +2578,10 @@ describe('Keyboard interactions', () => { Trigger - - Option A - - - Option B - - - Option C - - - Option D - + Option A + Option B + Option C + Option D `, @@ -2713,12 +2647,8 @@ describe('Keyboard interactions', () => { Option A Option B - - Option C - - - Option D - + Option C + Option D `, @@ -2751,15 +2681,9 @@ describe('Keyboard interactions', () => { Trigger Option A - - Option B - - - Option C - - - Option D - + Option B + Option C + Option D `, @@ -2788,18 +2712,10 @@ describe('Keyboard interactions', () => { Trigger - - Option A - - - Option B - - - Option C - - - Option D - + Option A + Option B + Option C + Option D `, @@ -2863,12 +2779,8 @@ describe('Keyboard interactions', () => { Trigger - - Option A - - - Option B - + Option A + Option B Option C Option D @@ -2901,15 +2813,9 @@ describe('Keyboard interactions', () => { Trigger - - Option A - - - Option B - - - Option C - + Option A + Option B + Option C Option D @@ -2939,18 +2845,10 @@ describe('Keyboard interactions', () => { Trigger - - Option A - - - Option B - - - Option C - - - Option D - + Option A + Option B + Option C + Option D `, @@ -3014,12 +2912,8 @@ describe('Keyboard interactions', () => { Trigger - - Option A - - - Option B - + Option A + Option B Option C Option D @@ -3052,15 +2946,9 @@ describe('Keyboard interactions', () => { Trigger - - Option A - - - Option B - - - Option C - + Option A + Option B + Option C Option D @@ -3090,18 +2978,10 @@ describe('Keyboard interactions', () => { Trigger - - Option A - - - Option B - - - Option C - - - Option D - + Option A + Option B + Option C + Option D `, @@ -3252,9 +3132,7 @@ describe('Keyboard interactions', () => { Trigger alice - - bob - + bob charlie @@ -3453,7 +3331,7 @@ describe('Mouse interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) }) ) @@ -3845,9 +3723,7 @@ describe('Mouse interactions', () => { Trigger alice - - bob - + bob charlie @@ -3874,9 +3750,7 @@ describe('Mouse interactions', () => { Trigger alice - - bob - + bob charlie @@ -3951,9 +3825,7 @@ describe('Mouse interactions', () => { Trigger alice - - bob - + bob charlie @@ -4031,9 +3903,7 @@ describe('Mouse interactions', () => { Trigger alice - - bob - + bob charlie @@ -4111,9 +3981,7 @@ describe('Mouse interactions', () => { Trigger alice - - bob - + bob charlie diff --git a/packages/@headlessui-vue/src/components/listbox/listbox.ts b/packages/@headlessui-vue/src/components/listbox/listbox.ts index cbc244d0de..812192da8f 100644 --- a/packages/@headlessui-vue/src/components/listbox/listbox.ts +++ b/packages/@headlessui-vue/src/components/listbox/listbox.ts @@ -130,8 +130,8 @@ export let Listbox = defineComponent({ { resolveItems: () => options.value, resolveActiveIndex: () => activeOptionIndex.value, - resolveId: option => option.id, - resolveDisabled: option => option.dataRef.disabled, + resolveId: (option) => option.id, + resolveDisabled: (option) => option.dataRef.disabled, } ) @@ -153,7 +153,7 @@ export let Listbox = defineComponent({ : options.value let matchingOption = reOrderedOptions.find( - option => + (option) => option.dataRef.textValue.startsWith(searchQuery.value) && !option.dataRef.disabled ) @@ -186,7 +186,7 @@ export let Listbox = defineComponent({ let nextOptions = options.value.slice() let currentActiveOption = activeOptionIndex.value !== null ? nextOptions[activeOptionIndex.value] : null - let idx = nextOptions.findIndex(a => a.id === id) + let idx = nextOptions.findIndex((a) => a.id === id) if (idx !== -1) nextOptions.splice(idx, 1) options.value = nextOptions activeOptionIndex.value = (() => { @@ -204,7 +204,7 @@ export let Listbox = defineComponent({ }, } - useWindowEvent('mousedown', event => { + useWindowEvent('mousedown', (event) => { let target = event.target as HTMLElement let active = document.activeElement @@ -245,30 +245,28 @@ export let Listbox = defineComponent({ export let ListboxLabel = defineComponent({ name: 'ListboxLabel', props: { as: { type: [Object, String], default: 'label' } }, - render() { + setup(props, { attrs, slots }) { let api = useListboxContext('ListboxLabel') + let id = `headlessui-listbox-label-${useId()}` - let slot = { open: api.listboxState.value === ListboxStates.Open, disabled: api.disabled.value } - let propsWeControl = { id: this.id, ref: 'el', onClick: this.handleClick } + function handleClick() { + dom(api.buttonRef)?.focus({ preventScroll: true }) + } - return render({ - props: { ...this.$props, ...propsWeControl }, - slot, - attrs: this.$attrs, - slots: this.$slots, - name: 'ListboxLabel', - }) - }, - setup() { - let api = useListboxContext('ListboxLabel') - let id = `headlessui-listbox-label-${useId()}` + return () => { + let slot = { + open: api.listboxState.value === ListboxStates.Open, + disabled: api.disabled.value, + } + let propsWeControl = { id, ref: api.labelRef, onClick: handleClick } - return { - id, - el: api.labelRef, - handleClick() { - dom(api.buttonRef)?.focus({ preventScroll: true }) - }, + return render({ + props: { ...props, ...propsWeControl }, + slot, + attrs, + slots, + name: 'ListboxLabel', + }) } }, }) @@ -280,37 +278,7 @@ export let ListboxButton = defineComponent({ props: { as: { type: [Object, String], default: 'button' }, }, - render() { - let api = useListboxContext('ListboxButton') - - let slot = { open: api.listboxState.value === ListboxStates.Open, disabled: api.disabled.value } - let propsWeControl = { - ref: 'el', - id: this.id, - type: this.type, - 'aria-haspopup': true, - 'aria-controls': dom(api.optionsRef)?.id, - 'aria-expanded': api.disabled.value - ? undefined - : api.listboxState.value === ListboxStates.Open, - 'aria-labelledby': api.labelRef.value - ? [dom(api.labelRef)?.id, this.id].join(' ') - : undefined, - disabled: api.disabled.value === true ? true : undefined, - onKeydown: this.handleKeyDown, - onKeyup: this.handleKeyUp, - onClick: this.handleClick, - } - - return render({ - props: { ...this.$props, ...propsWeControl }, - slot, - attrs: this.$attrs, - slots: this.$slots, - name: 'ListboxButton', - }) - }, - setup(props, { attrs }) { + setup(props, { attrs, slots }) { let api = useListboxContext('ListboxButton') let id = `headlessui-listbox-button-${useId()}` @@ -363,16 +331,39 @@ export let ListboxButton = defineComponent({ } } - return { - id, - el: api.buttonRef, - type: useResolveButtonType( - computed(() => ({ as: props.as, type: attrs.type })), - api.buttonRef - ), - handleKeyDown, - handleKeyUp, - handleClick, + let type = useResolveButtonType( + computed(() => ({ as: props.as, type: attrs.type })), + api.buttonRef + ) + + return () => { + let slot = { + open: api.listboxState.value === ListboxStates.Open, + disabled: api.disabled.value, + } + let propsWeControl = { + ref: api.buttonRef, + id, + type: type.value, + 'aria-haspopup': true, + 'aria-controls': dom(api.optionsRef)?.id, + 'aria-expanded': api.disabled.value + ? undefined + : api.listboxState.value === ListboxStates.Open, + 'aria-labelledby': api.labelRef.value ? [dom(api.labelRef)?.id, id].join(' ') : undefined, + disabled: api.disabled.value === true ? true : undefined, + onKeydown: handleKeyDown, + onKeyup: handleKeyUp, + onClick: handleClick, + } + + return render({ + props: { ...props, ...propsWeControl }, + slot, + attrs, + slots, + name: 'ListboxButton', + }) } }, }) @@ -386,36 +377,7 @@ export let ListboxOptions = defineComponent({ static: { type: Boolean, default: false }, unmount: { type: Boolean, default: true }, }, - render() { - let api = useListboxContext('ListboxOptions') - - let slot = { open: api.listboxState.value === ListboxStates.Open } - let propsWeControl = { - 'aria-activedescendant': - api.activeOptionIndex.value === null - ? undefined - : api.options.value[api.activeOptionIndex.value]?.id, - 'aria-labelledby': dom(api.labelRef)?.id ?? dom(api.buttonRef)?.id, - 'aria-orientation': api.orientation.value, - id: this.id, - onKeydown: this.handleKeyDown, - role: 'listbox', - tabIndex: 0, - ref: 'el', - } - let passThroughProps = this.$props - - return render({ - props: { ...passThroughProps, ...propsWeControl }, - slot, - attrs: this.$attrs, - slots: this.$slots, - features: Features.RenderStrategy | Features.Static, - visible: this.visible, - name: 'ListboxOptions', - }) - }, - setup() { + setup(props, { attrs, slots }) { let api = useListboxContext('ListboxOptions') let id = `headlessui-listbox-options-${useId()}` let searchDebounce = ref | null>(null) @@ -500,7 +462,33 @@ export let ListboxOptions = defineComponent({ return api.listboxState.value === ListboxStates.Open }) - return { id, el: api.optionsRef, handleKeyDown, visible } + return () => { + let slot = { open: api.listboxState.value === ListboxStates.Open } + let propsWeControl = { + 'aria-activedescendant': + api.activeOptionIndex.value === null + ? undefined + : api.options.value[api.activeOptionIndex.value]?.id, + 'aria-labelledby': dom(api.labelRef)?.id ?? dom(api.buttonRef)?.id, + 'aria-orientation': api.orientation.value, + id, + onKeydown: handleKeyDown, + role: 'listbox', + tabIndex: 0, + ref: api.optionsRef, + } + let passThroughProps = props + + return render({ + props: { ...passThroughProps, ...propsWeControl }, + slot, + attrs, + slots, + features: Features.RenderStrategy | Features.Static, + visible: visible.value, + name: 'ListboxOptions', + }) + } }, }) @@ -529,10 +517,7 @@ export let ListboxOption = defineComponent({ textValue: '', }) onMounted(() => { - let textValue = document - .getElementById(id) - ?.textContent?.toLowerCase() - .trim() + let textValue = document.getElementById(id)?.textContent?.toLowerCase().trim() if (textValue !== undefined) dataRef.value.textValue = textValue }) diff --git a/packages/@headlessui-vue/src/components/menu/menu.test.tsx b/packages/@headlessui-vue/src/components/menu/menu.test.tsx index fe34508d35..4d033b457d 100644 --- a/packages/@headlessui-vue/src/components/menu/menu.test.tsx +++ b/packages/@headlessui-vue/src/components/menu/menu.test.tsx @@ -1,4 +1,12 @@ -import { defineComponent, h, nextTick, reactive, ref, watch } from 'vue' +import { + ComponentOptionsWithoutProps, + defineComponent, + h, + nextTick, + reactive, + ref, + watch, +} from 'vue' import { render } from '../../test-utils/vue-testing-library' import { Menu, MenuButton, MenuItems, MenuItem } from './menu' import { TransitionChild } from '../transitions/transition' @@ -44,7 +52,7 @@ beforeAll(() => { afterAll(() => jest.restoreAllMocks()) function nextFrame() { - return new Promise(resolve => { + return new Promise((resolve) => { requestAnimationFrame(() => { requestAnimationFrame(() => { resolve() @@ -53,7 +61,7 @@ function nextFrame() { }) } -function renderTemplate(input: string | Partial[0]>) { +function renderTemplate(input: string | ComponentOptionsWithoutProps) { let defaultComponents = { Menu, MenuButton, MenuItems, MenuItem } if (typeof input === 'string') { @@ -395,7 +403,7 @@ describe('Rendering', () => { `, setup: () => ({ CustomButton: defineComponent({ - setup: props => () => h('button', { ...props }), + setup: (props) => () => h('button', { ...props }), }), }), }) @@ -433,7 +441,7 @@ describe('Rendering', () => { `, setup: () => ({ CustomButton: defineComponent({ - setup: props => () => h('div', props), + setup: (props) => () => h('div', props), }), }), }) @@ -810,7 +818,7 @@ describe('Rendering composition', () => { // Verify items are buttons now let items = getMenuItems() - items.forEach(item => + items.forEach((item) => assertMenuItem(item, { tag: 'button', attributes: { 'data-my-custom-button': 'true' } }) ) }) @@ -853,11 +861,11 @@ describe('Rendering composition', () => { expect.hasAssertions() - document.querySelectorAll('.outer').forEach(element => { + document.querySelectorAll('.outer').forEach((element) => { expect(element).not.toHaveAttribute('role', 'none') }) - document.querySelectorAll('.inner').forEach(element => { + document.querySelectorAll('.inner').forEach((element) => { expect(element).toHaveAttribute('role', 'none') }) }) @@ -1069,7 +1077,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) // Verify that the first menu item is active assertMenuLinkedWithMenuItem(items[0]) @@ -1398,7 +1406,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) assertMenuLinkedWithMenuItem(items[0]) }) @@ -1704,7 +1712,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) assertMenuLinkedWithMenuItem(items[0]) // Try to tab @@ -1750,7 +1758,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) assertMenuLinkedWithMenuItem(items[0]) // Try to Shift+Tab @@ -1798,7 +1806,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) // Verify that the first menu item is active assertMenuLinkedWithMenuItem(items[0]) @@ -1883,7 +1891,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) assertMenuLinkedWithMenuItem(items[0]) // We should be able to go down once @@ -1926,7 +1934,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) assertMenuLinkedWithMenuItem(items[1]) // We should be able to go down once @@ -1961,7 +1969,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) assertMenuLinkedWithMenuItem(items[2]) }) }) @@ -2002,7 +2010,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) // ! ALERT: The LAST item should now be active assertMenuLinkedWithMenuItem(items[2]) @@ -2055,7 +2063,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) assertMenuLinkedWithMenuItem(items[0]) }) @@ -2086,7 +2094,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) assertMenuLinkedWithMenuItem(items[2]) // We should not be able to go up (because those are disabled) @@ -2133,7 +2141,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) assertMenuLinkedWithMenuItem(items[2]) // We should be able to go down once @@ -2820,7 +2828,7 @@ describe('Mouse interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) }) it( diff --git a/packages/@headlessui-vue/src/components/menu/menu.ts b/packages/@headlessui-vue/src/components/menu/menu.ts index 1b25dcbc09..f154625ca2 100644 --- a/packages/@headlessui-vue/src/components/menu/menu.ts +++ b/packages/@headlessui-vue/src/components/menu/menu.ts @@ -96,8 +96,8 @@ export let Menu = defineComponent({ { resolveItems: () => items.value, resolveActiveIndex: () => activeItemIndex.value, - resolveId: item => item.id, - resolveDisabled: item => item.dataRef.disabled, + resolveId: (item) => item.id, + resolveDisabled: (item) => item.dataRef.disabled, } ) @@ -116,7 +116,7 @@ export let Menu = defineComponent({ : items.value let matchingItem = reOrderedItems.find( - item => item.dataRef.textValue.startsWith(searchQuery.value) && !item.dataRef.disabled + (item) => item.dataRef.textValue.startsWith(searchQuery.value) && !item.dataRef.disabled ) let matchIdx = matchingItem ? items.value.indexOf(matchingItem) : -1 @@ -144,7 +144,7 @@ export let Menu = defineComponent({ let nextItems = items.value.slice() let currentActiveItem = activeItemIndex.value !== null ? nextItems[activeItemIndex.value] : null - let idx = nextItems.findIndex(a => a.id === id) + let idx = nextItems.findIndex((a) => a.id === id) if (idx !== -1) nextItems.splice(idx, 1) items.value = nextItems activeItemIndex.value = (() => { @@ -158,7 +158,7 @@ export let Menu = defineComponent({ }, } - useWindowEvent('mousedown', event => { + useWindowEvent('mousedown', (event) => { let target = event.target as HTMLElement let active = document.activeElement @@ -172,6 +172,7 @@ export let Menu = defineComponent({ // @ts-expect-error Types of property 'dataRef' are incompatible. provide(MenuContext, api) + useOpenClosedProvider( computed(() => match(menuState.value, { @@ -194,31 +195,7 @@ export let MenuButton = defineComponent({ disabled: { type: Boolean, default: false }, as: { type: [Object, String], default: 'button' }, }, - render() { - let api = useMenuContext('MenuButton') - - let slot = { open: api.menuState.value === MenuStates.Open } - let propsWeControl = { - ref: 'el', - id: this.id, - type: this.type, - 'aria-haspopup': true, - 'aria-controls': dom(api.itemsRef)?.id, - 'aria-expanded': this.$props.disabled ? undefined : api.menuState.value === MenuStates.Open, - onKeydown: this.handleKeyDown, - onKeyup: this.handleKeyUp, - onClick: this.handleClick, - } - - return render({ - props: { ...this.$props, ...propsWeControl }, - slot, - attrs: this.$attrs, - slots: this.$slots, - name: 'MenuButton', - }) - }, - setup(props, { attrs }) { + setup(props, { attrs, slots }) { let api = useMenuContext('MenuButton') let id = `headlessui-menu-button-${useId()}` @@ -274,16 +251,32 @@ export let MenuButton = defineComponent({ } } - return { - id, - el: api.buttonRef, - type: useResolveButtonType( - computed(() => ({ as: props.as, type: attrs.type })), - api.buttonRef - ), - handleKeyDown, - handleKeyUp, - handleClick, + let type = useResolveButtonType( + computed(() => ({ as: props.as, type: attrs.type })), + api.buttonRef + ) + + return () => { + let slot = { open: api.menuState.value === MenuStates.Open } + let propsWeControl = { + ref: api.buttonRef, + id, + type: type.value, + 'aria-haspopup': true, + 'aria-controls': dom(api.itemsRef)?.id, + 'aria-expanded': props.disabled ? undefined : api.menuState.value === MenuStates.Open, + onKeydown: handleKeyDown, + onKeyup: handleKeyUp, + onClick: handleClick, + } + + return render({ + props: { ...props, ...propsWeControl }, + slot, + attrs, + slots, + name: 'MenuButton', + }) } }, }) @@ -295,36 +288,7 @@ export let MenuItems = defineComponent({ static: { type: Boolean, default: false }, unmount: { type: Boolean, default: true }, }, - render() { - let api = useMenuContext('MenuItems') - - let slot = { open: api.menuState.value === MenuStates.Open } - let propsWeControl = { - 'aria-activedescendant': - api.activeItemIndex.value === null - ? undefined - : api.items.value[api.activeItemIndex.value]?.id, - 'aria-labelledby': dom(api.buttonRef)?.id, - id: this.id, - onKeydown: this.handleKeyDown, - onKeyup: this.handleKeyUp, - role: 'menu', - tabIndex: 0, - ref: 'el', - } - let passThroughProps = this.$props - - return render({ - props: { ...passThroughProps, ...propsWeControl }, - slot, - attrs: this.$attrs, - slots: this.$slots, - features: Features.RenderStrategy | Features.Static, - visible: this.visible, - name: 'MenuItems', - }) - }, - setup() { + setup(props, { attrs, slots }) { let api = useMenuContext('MenuItems') let id = `headlessui-menu-items-${useId()}` let searchDebounce = ref | null>(null) @@ -430,7 +394,34 @@ export let MenuItems = defineComponent({ return api.menuState.value === MenuStates.Open }) - return { id, el: api.itemsRef, handleKeyDown, handleKeyUp, visible } + return () => { + let slot = { open: api.menuState.value === MenuStates.Open } + let propsWeControl = { + 'aria-activedescendant': + api.activeItemIndex.value === null + ? undefined + : api.items.value[api.activeItemIndex.value]?.id, + 'aria-labelledby': dom(api.buttonRef)?.id, + id, + onKeydown: handleKeyDown, + onKeyup: handleKeyUp, + role: 'menu', + tabIndex: 0, + ref: api.itemsRef, + } + + let passThroughProps = props + + return render({ + props: { ...passThroughProps, ...propsWeControl }, + slot, + attrs, + slots, + features: Features.RenderStrategy | Features.Static, + visible: visible.value, + name: 'MenuItems', + }) + } }, }) @@ -452,10 +443,7 @@ export let MenuItem = defineComponent({ let dataRef = ref({ disabled: props.disabled, textValue: '' }) onMounted(() => { - let textValue = document - .getElementById(id) - ?.textContent?.toLowerCase() - .trim() + let textValue = document.getElementById(id)?.textContent?.toLowerCase().trim() if (textValue !== undefined) dataRef.value.textValue = textValue }) diff --git a/packages/@headlessui-vue/src/components/popover/popover.test.ts b/packages/@headlessui-vue/src/components/popover/popover.test.ts index 7ba73f697d..3fabac6c15 100644 --- a/packages/@headlessui-vue/src/components/popover/popover.test.ts +++ b/packages/@headlessui-vue/src/components/popover/popover.test.ts @@ -1,4 +1,4 @@ -import { defineComponent, nextTick, ref, watch, h } from 'vue' +import { defineComponent, nextTick, ref, watch, h, ComponentOptionsWithoutProps } from 'vue' import { render } from '../../test-utils/vue-testing-library' import { Popover, PopoverGroup, PopoverButton, PopoverPanel, PopoverOverlay } from './popover' @@ -28,7 +28,7 @@ beforeAll(() => { afterAll(() => jest.restoreAllMocks()) -function renderTemplate(input: string | Partial[0]>) { +function renderTemplate(input: string | ComponentOptionsWithoutProps) { let defaultComponents = { Popover, PopoverGroup, @@ -345,9 +345,7 @@ describe('Rendering', () => { renderTemplate( html` - - Trigger - + Trigger ` ) @@ -361,14 +359,12 @@ describe('Rendering', () => { renderTemplate({ template: html` - - Trigger - + Trigger `, setup: () => ({ CustomButton: defineComponent({ - setup: props => () => h('button', { ...props }), + setup: (props) => () => h('button', { ...props }), }), }), }) @@ -383,9 +379,7 @@ describe('Rendering', () => { renderTemplate( html` - - Trigger - + Trigger ` ) @@ -399,14 +393,12 @@ describe('Rendering', () => { renderTemplate({ template: html` - - Trigger - + Trigger `, setup: () => ({ CustomButton: defineComponent({ - setup: props => () => h('div', props), + setup: (props) => () => h('div', props), }), }), }) @@ -569,9 +561,7 @@ describe('Rendering', () => { Trigger - - Link 1 - + Link 1 Link 2 @@ -757,9 +747,7 @@ describe('Composition', () => { Trigger - - {{JSON.stringify(data)}} - + {{JSON.stringify(data)}} `, @@ -787,9 +775,7 @@ describe('Composition', () => { Trigger - - {{JSON.stringify(data)}} - + {{JSON.stringify(data)}} `, diff --git a/packages/@headlessui-vue/src/components/popover/popover.ts b/packages/@headlessui-vue/src/components/popover/popover.ts index 2349ec2326..67d2d01c15 100644 --- a/packages/@headlessui-vue/src/components/popover/popover.ts +++ b/packages/@headlessui-vue/src/components/popover/popover.ts @@ -206,40 +206,7 @@ export let PopoverButton = defineComponent({ as: { type: [Object, String], default: 'button' }, disabled: { type: [Boolean], default: false }, }, - render() { - let api = usePopoverContext('PopoverButton') - - let slot = { open: api.popoverState.value === PopoverStates.Open } - let propsWeControl = this.isWithinPanel - ? { - ref: 'el', - type: this.type, - onKeydown: this.handleKeyDown, - onClick: this.handleClick, - } - : { - ref: 'el', - id: api.buttonId, - type: this.type, - 'aria-expanded': this.$props.disabled - ? undefined - : api.popoverState.value === PopoverStates.Open, - 'aria-controls': dom(api.panel) ? api.panelId : undefined, - disabled: this.$props.disabled ? true : undefined, - onKeydown: this.handleKeyDown, - onKeyup: this.handleKeyUp, - onClick: this.handleClick, - } - - return render({ - props: { ...this.$props, ...propsWeControl }, - slot, - attrs: this.$attrs, - slots: this.$slots, - name: 'PopoverButton', - }) - }, - setup(props, { attrs }) { + setup(props, { attrs, slots }) { let api = usePopoverContext('PopoverButton') let groupContext = usePopoverGroupContext() @@ -271,124 +238,153 @@ export let PopoverButton = defineComponent({ }) } - return { - isWithinPanel, - el: elementRef, - type: useResolveButtonType( - computed(() => ({ as: props.as, type: attrs.type })), - elementRef - ), - handleKeyDown(event: KeyboardEvent) { - if (isWithinPanel) { - if (api.popoverState.value === PopoverStates.Closed) return - switch (event.key) { - case Keys.Space: - case Keys.Enter: - event.preventDefault() // Prevent triggering a *click* event - event.stopPropagation() - api.closePopover() - dom(api.button)?.focus() // Re-focus the original opening Button - break - } - } else { - switch (event.key) { - case Keys.Space: - case Keys.Enter: - event.preventDefault() // Prevent triggering a *click* event - event.stopPropagation() - if (api.popoverState.value === PopoverStates.Closed) closeOthers?.(api.buttonId) - api.togglePopover() - break - - case Keys.Escape: - if (api.popoverState.value !== PopoverStates.Open) return closeOthers?.(api.buttonId) - if (!dom(api.button)) return - if (!dom(api.button)?.contains(document.activeElement)) return - event.preventDefault() - event.stopPropagation() - api.closePopover() - break - - case Keys.Tab: - if (api.popoverState.value !== PopoverStates.Open) return - if (!api.panel) return - if (!api.button) return - - // TODO: Revisit when handling Tab/Shift+Tab when using Portal's - if (event.shiftKey) { - // Check if the last focused element exists, and check that it is not inside button or panel itself - if (!previousActiveElementRef.value) return - if (dom(api.button)?.contains(previousActiveElementRef.value)) return - if (dom(api.panel)?.contains(previousActiveElementRef.value)) return - - // Check if the last focused element is *after* the button in the DOM - let focusableElements = getFocusableElements() - let previousIdx = focusableElements.indexOf( - previousActiveElementRef.value as HTMLElement - ) - let buttonIdx = focusableElements.indexOf(dom(api.button)!) - if (buttonIdx > previousIdx) return - - event.preventDefault() - event.stopPropagation() - - focusIn(dom(api.panel)!, Focus.Last) - } else { - event.preventDefault() - event.stopPropagation() - - focusIn(dom(api.panel)!, Focus.First) - } - - break - } - } - }, - handleKeyUp(event: KeyboardEvent) { - if (isWithinPanel) return - if (event.key === Keys.Space) { - // Required for firefox, event.preventDefault() in handleKeyDown for - // the Space key doesn't cancel the handleKeyUp, which in turn - // triggers a *click*. - event.preventDefault() - } - if (api.popoverState.value !== PopoverStates.Open) return - if (!api.panel) return - if (!api.button) return + let type = useResolveButtonType( + computed(() => ({ as: props.as, type: attrs.type })), + elementRef + ) - // TODO: Revisit when handling Tab/Shift+Tab when using Portal's + function handleKeyDown(event: KeyboardEvent) { + if (isWithinPanel) { + if (api.popoverState.value === PopoverStates.Closed) return switch (event.key) { - case Keys.Tab: - // Check if the last focused element exists, and check that it is not inside button or panel itself - if (!previousActiveElementRef.value) return - if (dom(api.button)?.contains(previousActiveElementRef.value)) return - if (dom(api.panel)?.contains(previousActiveElementRef.value)) return - - // Check if the last focused element is *after* the button in the DOM - let focusableElements = getFocusableElements() - let previousIdx = focusableElements.indexOf( - previousActiveElementRef.value as HTMLElement - ) - let buttonIdx = focusableElements.indexOf(dom(api.button)!) - if (buttonIdx > previousIdx) return + case Keys.Space: + case Keys.Enter: + event.preventDefault() // Prevent triggering a *click* event + event.stopPropagation() + api.closePopover() + dom(api.button)?.focus() // Re-focus the original opening Button + break + } + } else { + switch (event.key) { + case Keys.Space: + case Keys.Enter: + event.preventDefault() // Prevent triggering a *click* event + event.stopPropagation() + if (api.popoverState.value === PopoverStates.Closed) closeOthers?.(api.buttonId) + api.togglePopover() + break + case Keys.Escape: + if (api.popoverState.value !== PopoverStates.Open) return closeOthers?.(api.buttonId) + if (!dom(api.button)) return + if (!dom(api.button)?.contains(document.activeElement)) return event.preventDefault() event.stopPropagation() - focusIn(dom(api.panel)!, Focus.Last) + api.closePopover() + break + + case Keys.Tab: + if (api.popoverState.value !== PopoverStates.Open) return + if (!api.panel) return + if (!api.button) return + + // TODO: Revisit when handling Tab/Shift+Tab when using Portal's + if (event.shiftKey) { + // Check if the last focused element exists, and check that it is not inside button or panel itself + if (!previousActiveElementRef.value) return + if (dom(api.button)?.contains(previousActiveElementRef.value)) return + if (dom(api.panel)?.contains(previousActiveElementRef.value)) return + + // Check if the last focused element is *after* the button in the DOM + let focusableElements = getFocusableElements() + let previousIdx = focusableElements.indexOf( + previousActiveElementRef.value as HTMLElement + ) + let buttonIdx = focusableElements.indexOf(dom(api.button)!) + if (buttonIdx > previousIdx) return + + event.preventDefault() + event.stopPropagation() + + focusIn(dom(api.panel)!, Focus.Last) + } else { + event.preventDefault() + event.stopPropagation() + + focusIn(dom(api.panel)!, Focus.First) + } + break } - }, - handleClick() { - if (props.disabled) return - if (isWithinPanel) { - api.closePopover() - dom(api.button)?.focus() // Re-focus the original opening Button - } else { - if (api.popoverState.value === PopoverStates.Closed) closeOthers?.(api.buttonId) - dom(api.button)?.focus() - api.togglePopover() - } - }, + } + } + + function handleKeyUp(event: KeyboardEvent) { + if (isWithinPanel) return + if (event.key === Keys.Space) { + // Required for firefox, event.preventDefault() in handleKeyDown for + // the Space key doesn't cancel the handleKeyUp, which in turn + // triggers a *click*. + event.preventDefault() + } + if (api.popoverState.value !== PopoverStates.Open) return + if (!api.panel) return + if (!api.button) return + + // TODO: Revisit when handling Tab/Shift+Tab when using Portal's + switch (event.key) { + case Keys.Tab: + // Check if the last focused element exists, and check that it is not inside button or panel itself + if (!previousActiveElementRef.value) return + if (dom(api.button)?.contains(previousActiveElementRef.value)) return + if (dom(api.panel)?.contains(previousActiveElementRef.value)) return + + // Check if the last focused element is *after* the button in the DOM + let focusableElements = getFocusableElements() + let previousIdx = focusableElements.indexOf(previousActiveElementRef.value as HTMLElement) + let buttonIdx = focusableElements.indexOf(dom(api.button)!) + if (buttonIdx > previousIdx) return + + event.preventDefault() + event.stopPropagation() + focusIn(dom(api.panel)!, Focus.Last) + break + } + } + + function handleClick() { + if (props.disabled) return + if (isWithinPanel) { + api.closePopover() + dom(api.button)?.focus() // Re-focus the original opening Button + } else { + if (api.popoverState.value === PopoverStates.Closed) closeOthers?.(api.buttonId) + dom(api.button)?.focus() + api.togglePopover() + } + } + + return () => { + let slot = { open: api.popoverState.value === PopoverStates.Open } + let propsWeControl = isWithinPanel + ? { + ref: elementRef, + type: type.value, + onKeydown: handleKeyDown, + onClick: handleClick, + } + : { + ref: elementRef, + id: api.buttonId, + type: type.value, + 'aria-expanded': props.disabled + ? undefined + : api.popoverState.value === PopoverStates.Open, + 'aria-controls': dom(api.panel) ? api.panelId : undefined, + disabled: props.disabled ? true : undefined, + onKeydown: handleKeyDown, + onKeyup: handleKeyUp, + onClick: handleClick, + } + + return render({ + props: { ...props, ...propsWeControl }, + slot, + attrs: attrs, + slots: slots, + name: 'PopoverButton', + }) } }, }) @@ -402,29 +398,9 @@ export let PopoverOverlay = defineComponent({ static: { type: Boolean, default: false }, unmount: { type: Boolean, default: true }, }, - render() { - let api = usePopoverContext('PopoverOverlay') - - let slot = { open: api.popoverState.value === PopoverStates.Open } - let propsWeControl = { - id: this.id, - ref: 'el', - 'aria-hidden': true, - onClick: this.handleClick, - } - - return render({ - props: { ...this.$props, ...propsWeControl }, - slot, - attrs: this.$attrs, - slots: this.$slots, - features: Features.RenderStrategy | Features.Static, - visible: this.visible, - name: 'PopoverOverlay', - }) - }, - setup() { + setup(props, { attrs, slots }) { let api = usePopoverContext('PopoverOverlay') + let id = `headlessui-popover-overlay-${useId()}` let usesOpenClosedState = useOpenClosed() let visible = computed(() => { @@ -435,12 +411,27 @@ export let PopoverOverlay = defineComponent({ return api.popoverState.value === PopoverStates.Open }) - return { - id: `headlessui-popover-overlay-${useId()}`, - handleClick() { - api.closePopover() - }, - visible, + function handleClick() { + api.closePopover() + } + + return () => { + let slot = { open: api.popoverState.value === PopoverStates.Open } + let propsWeControl = { + id, + 'aria-hidden': true, + onClick: handleClick, + } + + return render({ + props: { ...props, ...propsWeControl }, + slot, + attrs, + slots, + features: Features.RenderStrategy | Features.Static, + visible: visible.value, + name: 'PopoverOverlay', + }) } }, }) @@ -455,31 +446,7 @@ export let PopoverPanel = defineComponent({ unmount: { type: Boolean, default: true }, focus: { type: Boolean, default: false }, }, - render() { - let api = usePopoverContext('PopoverPanel') - - let slot = { - open: api.popoverState.value === PopoverStates.Open, - close: api.close, - } - - let propsWeControl = { - ref: 'el', - id: this.id, - onKeydown: this.handleKeyDown, - } - - return render({ - props: { ...this.$props, ...propsWeControl }, - slot, - attrs: this.$attrs, - slots: this.$slots, - features: Features.RenderStrategy | Features.Static, - visible: this.visible, - name: 'PopoverPanel', - }) - }, - setup(props) { + setup(props, { attrs, slots }) { let { focus } = props let api = usePopoverContext('PopoverPanel') @@ -528,7 +495,7 @@ export let PopoverPanel = defineComponent({ let nextElements = elements .splice(buttonIdx + 1) // Elements after button - .filter(element => !dom(api.panel)?.contains(element)) // Ignore items in panel + .filter((element) => !dom(api.panel)?.contains(element)) // Ignore items in panel // Try to focus the next element, however it could fail if we are in a // Portal that happens to be the very last one in the DOM. In that @@ -563,23 +530,41 @@ export let PopoverPanel = defineComponent({ return api.popoverState.value === PopoverStates.Open }) - return { - id: api.panelId, - el: api.panel, - handleKeyDown(event: KeyboardEvent) { - switch (event.key) { - case Keys.Escape: - if (api.popoverState.value !== PopoverStates.Open) return - if (!dom(api.panel)) return - if (!dom(api.panel)?.contains(document.activeElement)) return - event.preventDefault() - event.stopPropagation() - api.closePopover() - dom(api.button)?.focus() - break - } - }, - visible, + function handleKeyDown(event: KeyboardEvent) { + switch (event.key) { + case Keys.Escape: + if (api.popoverState.value !== PopoverStates.Open) return + if (!dom(api.panel)) return + if (!dom(api.panel)?.contains(document.activeElement)) return + event.preventDefault() + event.stopPropagation() + api.closePopover() + dom(api.button)?.focus() + break + } + } + + return () => { + let slot = { + open: api.popoverState.value === PopoverStates.Open, + close: api.close, + } + + let propsWeControl = { + ref: api.panel, + id: api.panelId, + onKeydown: handleKeyDown, + } + + return render({ + props: { ...props, ...propsWeControl }, + slot, + attrs, + slots, + features: Features.RenderStrategy | Features.Static, + visible: visible.value, + name: 'PopoverPanel', + }) } }, }) @@ -591,18 +576,7 @@ export let PopoverGroup = defineComponent({ props: { as: { type: [Object, String], default: 'div' }, }, - render() { - let propsWeControl = { ref: 'el' } - - return render({ - props: { ...this.$props, ...propsWeControl }, - slot: {}, - attrs: this.$attrs, - slots: this.$slots, - name: 'PopoverGroup', - }) - }, - setup() { + setup(props, { attrs, slots }) { let groupRef = ref(null) let popovers = ref([]) @@ -624,7 +598,7 @@ export let PopoverGroup = defineComponent({ if (dom(groupRef)?.contains(element)) return true // Check if the focus is in one of the button or panel elements. This is important in case you are rendering inside a Portal. - return popovers.value.some(bag => { + return popovers.value.some((bag) => { return ( document.getElementById(bag.buttonId)?.contains(element) || document.getElementById(bag.panelId)?.contains(element) @@ -645,6 +619,16 @@ export let PopoverGroup = defineComponent({ closeOthers, }) - return { el: groupRef } + return () => { + let propsWeControl = { ref: groupRef } + + return render({ + props: { ...props, ...propsWeControl }, + slot: {}, + attrs, + slots, + name: 'PopoverGroup', + }) + } }, }) diff --git a/packages/@headlessui-vue/src/components/portal/portal.test.ts b/packages/@headlessui-vue/src/components/portal/portal.test.ts index ee03bab472..0c1055e783 100644 --- a/packages/@headlessui-vue/src/components/portal/portal.test.ts +++ b/packages/@headlessui-vue/src/components/portal/portal.test.ts @@ -1,4 +1,4 @@ -import { defineComponent, ref, nextTick } from 'vue' +import { defineComponent, ref, nextTick, ComponentOptionsWithoutProps } from 'vue' import { render } from '../../test-utils/vue-testing-library' import { Portal, PortalGroup } from './portal' @@ -22,7 +22,7 @@ beforeAll(() => { afterAll(() => jest.restoreAllMocks()) -function renderTemplate(input: string | Partial[0]>) { +function renderTemplate(input: string | ComponentOptionsWithoutProps) { let defaultComponents = { Portal, PortalGroup } if (typeof input === 'string') { @@ -108,12 +108,8 @@ it('should cleanup the Portal root when the last Portal is unmounted', async () renderTemplate({ template: html`
- - + +

Contents 1 ...

@@ -182,19 +178,11 @@ it('should be possible to render multiple portals at the same time', async () => renderTemplate({ template: html`
- - - - - + + + + +

Contents 1 ...

@@ -269,12 +257,8 @@ it('should be possible to tamper with the modal root and restore correctly', asy renderTemplate({ template: html`
- - + +

Contents 1 ...

@@ -325,9 +309,7 @@ it('should be possible to force the Portal into a specific element using PortalG renderTemplate({ template: html`
- +
@@ -346,6 +328,6 @@ it('should be possible to force the Portal into a specific element using PortalG await new Promise(nextTick) expect(document.body.innerHTML).toMatchInlineSnapshot( - `"
B
"` + `"
B
"` ) }) diff --git a/packages/@headlessui-vue/src/components/radio-group/radio-group.test.ts b/packages/@headlessui-vue/src/components/radio-group/radio-group.test.ts index 1701836541..aacac780d7 100644 --- a/packages/@headlessui-vue/src/components/radio-group/radio-group.test.ts +++ b/packages/@headlessui-vue/src/components/radio-group/radio-group.test.ts @@ -1,4 +1,4 @@ -import { defineComponent, nextTick, ref, watch, reactive } from 'vue' +import { defineComponent, nextTick, ref, watch, reactive, ComponentOptionsWithoutProps } from 'vue' import { render } from '../../test-utils/vue-testing-library' import { RadioGroup, RadioGroupOption, RadioGroupLabel, RadioGroupDescription } from './radio-group' @@ -25,7 +25,7 @@ beforeAll(() => { afterAll(() => jest.restoreAllMocks()) function nextFrame() { - return new Promise(resolve => { + return new Promise((resolve) => { requestAnimationFrame(() => { requestAnimationFrame(() => { resolve() @@ -34,7 +34,7 @@ function nextFrame() { }) } -function renderTemplate(input: string | Partial[0]>) { +function renderTemplate(input: string | ComponentOptionsWithoutProps) { let defaultComponents = { RadioGroup, RadioGroupOption, RadioGroupLabel, RadioGroupDescription } if (typeof input === 'string') { @@ -86,9 +86,7 @@ describe('Safe guards', () => { it('should be possible to render a RadioGroup without options and without crashing', () => { renderTemplate({ - template: html` - - `, + template: html` `, setup() { let deliveryMethod = ref(undefined) return { deliveryMethod } diff --git a/packages/@headlessui-vue/src/components/radio-group/radio-group.ts b/packages/@headlessui-vue/src/components/radio-group/radio-group.ts index dba087a802..44481eea3f 100644 --- a/packages/@headlessui-vue/src/components/radio-group/radio-group.ts +++ b/packages/@headlessui-vue/src/components/radio-group/radio-group.ts @@ -17,7 +17,7 @@ import { dom } from '../../utils/dom' import { Keys } from '../../keyboard' import { focusIn, Focus, FocusResult } from '../../utils/focus-management' import { useId } from '../../hooks/use-id' -import { render } from '../../utils/render' +import { omit, render } from '../../utils/render' import { Label, useLabels } from '../label/label' import { Description, useDescriptions } from '../description/description' import { useTreeWalker } from '../../hooks/use-tree-walker' @@ -66,27 +66,7 @@ export let RadioGroup = defineComponent({ disabled: { type: [Boolean], default: false }, modelValue: { type: [Object, String, Number, Boolean] }, }, - render() { - let { modelValue, disabled, ...passThroughProps } = this.$props - - let propsWeControl = { - ref: 'el', - id: this.id, - role: 'radiogroup', - 'aria-labelledby': this.labelledby, - 'aria-describedby': this.describedby, - onKeydown: this.handleKeyDown, - } - - return render({ - props: { ...passThroughProps, ...propsWeControl }, - slot: {}, - attrs: this.$attrs, - slots: this.$slots, - name: 'RadioGroup', - }) - }, - setup(props, { emit }) { + setup(props, { emit, attrs, slots }) { let radioGroupRef = ref(null) let options = ref([]) let labelledby = useLabels({ name: 'RadioGroupLabel' }) @@ -99,19 +79,19 @@ export let RadioGroup = defineComponent({ value, disabled: computed(() => props.disabled), firstOption: computed(() => - options.value.find(option => { + options.value.find((option) => { if (option.propsRef.disabled) return false return true }) ), containsCheckedOption: computed(() => - options.value.some(option => toRaw(option.propsRef.value) === toRaw(props.modelValue)) + options.value.some((option) => toRaw(option.propsRef.value) === toRaw(props.modelValue)) ), change(nextValue: unknown) { if (props.disabled) return false if (value.value === nextValue) return false let nextOption = options.value.find( - option => toRaw(option.propsRef.value) === toRaw(nextValue) + (option) => toRaw(option.propsRef.value) === toRaw(nextValue) )?.propsRef if (nextOption?.disabled) return false emit('update:modelValue', nextValue) @@ -129,7 +109,7 @@ export let RadioGroup = defineComponent({ options.value.sort((a, z) => orderMap[a.id] - orderMap[z.id]) }, unregisterOption(id: Option['id']) { - let idx = options.value.findIndex(radio => radio.id === id) + let idx = options.value.findIndex((radio) => radio.id === id) if (idx === -1) return options.value.splice(idx, 1) }, @@ -155,8 +135,8 @@ export let RadioGroup = defineComponent({ if (!radioGroupRef.value.contains(event.target as HTMLElement)) return let all = options.value - .filter(option => option.propsRef.disabled === false) - .map(radio => radio.element) as HTMLElement[] + .filter((option) => option.propsRef.disabled === false) + .map((radio) => radio.element) as HTMLElement[] switch (event.key) { case Keys.ArrowLeft: @@ -169,7 +149,7 @@ export let RadioGroup = defineComponent({ if (result === FocusResult.Success) { let activeOption = options.value.find( - option => option.element === document.activeElement + (option) => option.element === document.activeElement ) if (activeOption) api.change(activeOption.propsRef.value) } @@ -186,7 +166,7 @@ export let RadioGroup = defineComponent({ if (result === FocusResult.Success) { let activeOption = options.value.find( - option => option.element === document.activeElement + (option) => option.element === document.activeElement ) if (activeOption) api.change(activeOption.propsRef.value) } @@ -199,7 +179,7 @@ export let RadioGroup = defineComponent({ event.stopPropagation() let activeOption = options.value.find( - option => option.element === document.activeElement + (option) => option.element === document.activeElement ) if (activeOption) api.change(activeOption.propsRef.value) } @@ -209,12 +189,25 @@ export let RadioGroup = defineComponent({ let id = `headlessui-radiogroup-${useId()}` - return { - id, - labelledby, - describedby, - el: radioGroupRef, - handleKeyDown, + return () => { + let { modelValue, disabled, ...passThroughProps } = props + + let propsWeControl = { + ref: radioGroupRef, + id, + role: 'radiogroup', + 'aria-labelledby': labelledby.value, + 'aria-describedby': describedby.value, + onKeydown: handleKeyDown, + } + + return render({ + props: { ...passThroughProps, ...propsWeControl }, + slot: {}, + attrs, + slots, + name: 'RadioGroup', + }) } }, }) @@ -233,38 +226,7 @@ export let RadioGroupOption = defineComponent({ value: { type: [Object, String, Number, Boolean] }, disabled: { type: Boolean, default: false }, }, - render() { - let { value, disabled, ...passThroughProps } = this.$props - - let slot = { - checked: this.checked, - disabled: this.disabled, - active: Boolean(this.state & OptionState.Active), - } - - let propsWeControl = { - id: this.id, - ref: 'el', - role: 'radio', - 'aria-checked': this.checked ? 'true' : 'false', - 'aria-labelledby': this.labelledby, - 'aria-describedby': this.describedby, - 'aria-disabled': this.disabled ? true : undefined, - tabIndex: this.tabIndex, - onClick: this.disabled ? undefined : this.handleClick, - onFocus: this.disabled ? undefined : this.handleFocus, - onBlur: this.disabled ? undefined : this.handleBlur, - } - - return render({ - props: { ...passThroughProps, ...propsWeControl }, - slot, - attrs: this.$attrs, - slots: this.$slots, - name: 'RadioGroupOption', - }) - }, - setup(props) { + setup(props, { attrs, slots }) { let api = useRadioGroupContext('RadioGroupOption') let id = `headlessui-radiogroup-option-${useId()}` let labelledby = useLabels({ name: 'RadioGroupLabel' }) @@ -280,33 +242,58 @@ export let RadioGroupOption = defineComponent({ let isFirstOption = computed(() => api.firstOption.value?.id === id) let disabled = computed(() => api.disabled.value || props.disabled) let checked = computed(() => toRaw(api.value.value) === toRaw(props.value)) + let tabIndex = computed(() => { + if (disabled.value) return -1 + if (checked.value) return 0 + if (!api.containsCheckedOption.value && isFirstOption.value) return 0 + return -1 + }) - return { - id, - el: optionRef, - labelledby, - describedby, - state, - disabled, - checked, - tabIndex: computed(() => { - if (disabled.value) return -1 - if (checked.value) return 0 - if (!api.containsCheckedOption.value && isFirstOption.value) return 0 - return -1 - }), - handleClick() { - if (!api.change(props.value)) return - - state.value |= OptionState.Active - optionRef.value?.focus() - }, - handleFocus() { - state.value |= OptionState.Active - }, - handleBlur() { - state.value &= ~OptionState.Active - }, + function handleClick() { + if (!api.change(props.value)) return + + state.value |= OptionState.Active + optionRef.value?.focus() + } + + function handleFocus() { + state.value |= OptionState.Active + } + + function handleBlur() { + state.value &= ~OptionState.Active + } + + return () => { + let passThroughProps = omit(props, ['value', 'disabled']) + + let slot = { + checked: checked.value, + disabled: disabled.value, + active: Boolean(state.value & OptionState.Active), + } + + let propsWeControl = { + id, + ref: optionRef, + role: 'radio', + 'aria-checked': checked.value ? 'true' : 'false', + 'aria-labelledby': labelledby.value, + 'aria-describedby': describedby.value, + 'aria-disabled': disabled.value ? true : undefined, + tabIndex: tabIndex.value, + onClick: disabled.value ? undefined : handleClick, + onFocus: disabled.value ? undefined : handleFocus, + onBlur: disabled.value ? undefined : handleBlur, + } + + return render({ + props: { ...passThroughProps, ...propsWeControl }, + slot, + attrs, + slots, + name: 'RadioGroupOption', + }) } }, }) diff --git a/packages/@headlessui-vue/src/components/switch/switch.test.tsx b/packages/@headlessui-vue/src/components/switch/switch.test.tsx index 7cc092f559..207239c57c 100644 --- a/packages/@headlessui-vue/src/components/switch/switch.test.tsx +++ b/packages/@headlessui-vue/src/components/switch/switch.test.tsx @@ -1,4 +1,4 @@ -import { defineComponent, ref, watch, h } from 'vue' +import { defineComponent, ref, watch, h, ComponentOptionsWithoutProps } from 'vue' import { render } from '../../test-utils/vue-testing-library' import { Switch, SwitchLabel, SwitchDescription, SwitchGroup } from './switch' @@ -16,7 +16,7 @@ import { suppressConsoleLogs } from '../../test-utils/suppress-console-logs' jest.mock('../../hooks/use-id') -function renderTemplate(input: string | Partial[0]>) { +function renderTemplate(input: string | ComponentOptionsWithoutProps) { let defaultComponents = { Switch, SwitchLabel, SwitchDescription, SwitchGroup } if (typeof input === 'string') { @@ -35,9 +35,7 @@ function renderTemplate(input: string | Partial { it('should be possible to render a Switch without crashing', () => { renderTemplate({ - template: html` - - `, + template: html` `, setup: () => ({ checked: ref(false) }), }) }) @@ -72,9 +70,7 @@ describe('Rendering', () => { it('should be possible to render an (on) Switch using an `as` prop', () => { renderTemplate({ - template: html` - - `, + template: html` `, setup: () => ({ checked: ref(true) }), }) assertSwitch({ state: SwitchState.On, tag: 'span' }) @@ -82,9 +78,7 @@ describe('Rendering', () => { it('should be possible to render an (off) Switch using an `as` prop', () => { renderTemplate({ - template: html` - - `, + template: html` `, setup: () => ({ checked: ref(false) }), }) assertSwitch({ state: SwitchState.Off, tag: 'span' }) @@ -106,11 +100,7 @@ describe('Rendering', () => { describe('`type` attribute', () => { it('should set the `type` to "button" by default', async () => { renderTemplate({ - template: html` - - Trigger - - `, + template: html` Trigger `, setup: () => ({ checked: ref(false) }), }) @@ -119,11 +109,7 @@ describe('Rendering', () => { it('should not set the `type` to "button" if it already contains a `type`', async () => { renderTemplate({ - template: html` - - Trigger - - `, + template: html` Trigger `, setup: () => ({ checked: ref(false) }), }) @@ -134,15 +120,11 @@ describe('Rendering', () => { 'should set the `type` to "button" when using the `as` prop which resolves to a "button"', suppressConsoleLogs(async () => { renderTemplate({ - template: html` - - Trigger - - `, + template: html` Trigger `, setup: () => ({ checked: ref(false), CustomButton: defineComponent({ - setup: props => () => h('button', { ...props }), + setup: (props) => () => h('button', { ...props }), }), }), }) @@ -155,11 +137,7 @@ describe('Rendering', () => { it('should not set the type if the "as" prop is not a "button"', async () => { renderTemplate({ - template: html` - - Trigger - - `, + template: html` Trigger `, setup: () => ({ checked: ref(false) }), }) @@ -170,15 +148,11 @@ describe('Rendering', () => { 'should not set the `type` to "button" when using the `as` prop which resolves to a "div"', suppressConsoleLogs(async () => { renderTemplate({ - template: html` - - Trigger - - `, + template: html` Trigger `, setup: () => ({ checked: ref(false), CustomButton: defineComponent({ - setup: props => () => h('div', props), + setup: (props) => () => h('div', props), }), }), }) @@ -213,9 +187,7 @@ describe('Render composition', () => { template: html` Label B - - Label A - + Label A `, setup: () => ({ checked: ref(false) }), @@ -234,9 +206,7 @@ describe('Render composition', () => { renderTemplate({ template: html` - - Label A - + Label A Label B `, @@ -370,9 +340,7 @@ describe('Keyboard interactions', () => { it('should be possible to toggle the Switch with Space', async () => { let handleChange = jest.fn() renderTemplate({ - template: html` - - `, + template: html` `, setup() { let checked = ref(false) watch([checked], () => handleChange(checked.value)) @@ -404,9 +372,7 @@ describe('Keyboard interactions', () => { it('should not be possible to use Enter to toggle the Switch', async () => { let handleChange = jest.fn() renderTemplate({ - template: html` - - `, + template: html` `, setup() { let checked = ref(false) watch([checked], () => handleChange(checked.value)) @@ -461,9 +427,7 @@ describe('Mouse interactions', () => { it('should be possible to toggle the Switch with a click', async () => { let handleChange = jest.fn() renderTemplate({ - template: html` - - `, + template: html` `, setup() { let checked = ref(false) watch([checked], () => handleChange(checked.value)) diff --git a/packages/@headlessui-vue/src/components/switch/switch.ts b/packages/@headlessui-vue/src/components/switch/switch.ts index ae202f8786..8ca770ea35 100644 --- a/packages/@headlessui-vue/src/components/switch/switch.ts +++ b/packages/@headlessui-vue/src/components/switch/switch.ts @@ -64,31 +64,8 @@ export let Switch = defineComponent({ as: { type: [Object, String], default: 'button' }, modelValue: { type: Boolean, default: false }, }, - render() { - let slot = { checked: this.$props.modelValue } - let propsWeControl = { - id: this.id, - ref: 'el', - role: 'switch', - type: this.type, - tabIndex: 0, - 'aria-checked': this.$props.modelValue, - 'aria-labelledby': this.labelledby, - 'aria-describedby': this.describedby, - onClick: this.handleClick, - onKeyup: this.handleKeyUp, - onKeypress: this.handleKeyPress, - } - return render({ - props: { ...this.$props, ...propsWeControl }, - slot, - attrs: this.$attrs, - slots: this.$slots, - name: 'Switch', - }) - }, - setup(props, { emit, attrs }) { + setup(props, { emit, attrs, slots }) { let api = inject(GroupContext, null) let id = `headlessui-switch-${useId()}` @@ -98,28 +75,49 @@ export let Switch = defineComponent({ let internalSwitchRef = ref(null) let switchRef = api === null ? internalSwitchRef : api.switchRef + let type = useResolveButtonType( + computed(() => ({ as: props.as, type: attrs.type })), + switchRef + ) + + function handleClick(event: MouseEvent) { + event.preventDefault() + toggle() + } - return { - id, - el: switchRef, - type: useResolveButtonType( - computed(() => ({ as: props.as, type: attrs.type })), - switchRef - ), - labelledby: api?.labelledby, - describedby: api?.describedby, - handleClick(event: MouseEvent) { - event.preventDefault() - toggle() - }, - handleKeyUp(event: KeyboardEvent) { - if (event.key !== Keys.Tab) event.preventDefault() - if (event.key === Keys.Space) toggle() - }, - // This is needed so that we can "cancel" the click event when we use the `Enter` key on a button. - handleKeyPress(event: KeyboardEvent) { - event.preventDefault() - }, + function handleKeyUp(event: KeyboardEvent) { + if (event.key !== Keys.Tab) event.preventDefault() + if (event.key === Keys.Space) toggle() + } + + // This is needed so that we can "cancel" the click event when we use the `Enter` key on a button. + function handleKeyPress(event: KeyboardEvent) { + event.preventDefault() + } + + return () => { + let slot = { checked: props.modelValue } + let propsWeControl = { + id, + ref: switchRef, + role: 'switch', + type: type.value, + tabIndex: 0, + 'aria-checked': props.modelValue, + 'aria-labelledby': api?.labelledby.value, + 'aria-describedby': api?.describedby.value, + onClick: handleClick, + onKeyup: handleKeyUp, + onKeypress: handleKeyPress, + } + + return render({ + props: { ...props, ...propsWeControl }, + slot, + attrs, + slots, + name: 'Switch', + }) } }, }) diff --git a/packages/@headlessui-vue/src/components/tabs/tabs.test.ts b/packages/@headlessui-vue/src/components/tabs/tabs.test.ts index e4573d0368..2ec3f3027a 100644 --- a/packages/@headlessui-vue/src/components/tabs/tabs.test.ts +++ b/packages/@headlessui-vue/src/components/tabs/tabs.test.ts @@ -1,4 +1,4 @@ -import { defineComponent, nextTick, ref } from 'vue' +import { ComponentOptionsWithoutProps, defineComponent, nextTick, ref } from 'vue' import { render } from '../../test-utils/vue-testing-library' import { TabGroup, TabList, Tab, TabPanels, TabPanel } from './tabs' import { suppressConsoleLogs } from '../../test-utils/suppress-console-logs' @@ -20,7 +20,7 @@ beforeAll(() => { afterAll(() => jest.restoreAllMocks()) -function renderTemplate(input: string | Partial[0]>) { +function renderTemplate(input: string | ComponentOptionsWithoutProps) { let defaultComponents = { TabGroup, TabList, Tab, TabPanels, TabPanel } if (typeof input === 'string') { diff --git a/packages/@headlessui-vue/src/components/tabs/tabs.ts b/packages/@headlessui-vue/src/components/tabs/tabs.ts index d7f8a1888c..b01e779a34 100644 --- a/packages/@headlessui-vue/src/components/tabs/tabs.ts +++ b/packages/@headlessui-vue/src/components/tabs/tabs.ts @@ -102,8 +102,8 @@ export let TabGroup = defineComponent({ if (api.tabs.value.length <= 0) return if (props.selectedIndex === null && selectedIndex.value !== null) return - let tabs = api.tabs.value.map(tab => dom(tab)).filter(Boolean) as HTMLElement[] - let focusableTabs = tabs.filter(tab => !tab.hasAttribute('disabled')) + let tabs = api.tabs.value.map((tab) => dom(tab)).filter(Boolean) as HTMLElement[] + let focusableTabs = tabs.filter((tab) => !tab.hasAttribute('disabled')) let indexToSet = props.selectedIndex ?? props.defaultIndex @@ -122,7 +122,7 @@ export let TabGroup = defineComponent({ let before = tabs.slice(0, indexToSet) let after = tabs.slice(indexToSet) - let next = [...after, ...before].find(tab => focusableTabs.includes(tab)) + let next = [...after, ...before].find((tab) => focusableTabs.includes(tab)) if (!next) return selectedIndex.value = tabs.indexOf(next) @@ -181,33 +181,7 @@ export let Tab = defineComponent({ as: { type: [Object, String], default: 'button' }, disabled: { type: [Boolean], default: false }, }, - render() { - let api = useTabsContext('Tab') - - let slot = { selected: this.selected } - let propsWeControl = { - ref: 'el', - onKeydown: this.handleKeyDown, - onFocus: api.activation.value === 'manual' ? this.handleFocus : this.handleSelection, - onClick: this.handleSelection, - id: this.id, - role: 'tab', - type: this.type, - 'aria-controls': api.panels.value[this.myIndex]?.value?.id, - 'aria-selected': this.selected, - tabIndex: this.selected ? 0 : -1, - disabled: this.$props.disabled ? true : undefined, - } - - return render({ - props: { ...this.$props, ...propsWeControl }, - slot, - attrs: this.$attrs, - slots: this.$slots, - name: 'Tab', - }) - }, - setup(props, { attrs }) { + setup(props, { attrs, slots }) { let api = useTabsContext('Tab') let id = `headlessui-tabs-tab-${useId()}` @@ -220,7 +194,7 @@ export let Tab = defineComponent({ let selected = computed(() => myIndex.value === api.selectedIndex.value) function handleKeyDown(event: KeyboardEvent) { - let list = api.tabs.value.map(tab => dom(tab)).filter(Boolean) as HTMLElement[] + let list = api.tabs.value.map((tab) => dom(tab)).filter(Boolean) as HTMLElement[] if (event.key === Keys.Space || event.key === Keys.Enter) { event.preventDefault() @@ -271,18 +245,34 @@ export let Tab = defineComponent({ api.setSelectedIndex(myIndex.value) } - return { - el: tabRef, - id, - selected, - myIndex, - type: useResolveButtonType( - computed(() => ({ as: props.as, type: attrs.type })), - tabRef - ), - handleKeyDown, - handleFocus, - handleSelection, + let type = useResolveButtonType( + computed(() => ({ as: props.as, type: attrs.type })), + tabRef + ) + + return () => { + let slot = { selected: selected.value } + let propsWeControl = { + ref: tabRef, + onKeydown: handleKeyDown, + onFocus: api.activation.value === 'manual' ? handleFocus : handleSelection, + onClick: handleSelection, + id, + role: 'tab', + type: type.value, + 'aria-controls': api.panels.value[myIndex.value]?.value?.id, + 'aria-selected': selected.value, + tabIndex: selected.value ? 0 : -1, + disabled: props.disabled ? true : undefined, + } + + return render({ + props: { ...props, ...propsWeControl }, + slot, + attrs, + slots, + name: 'Tab', + }) } }, }) @@ -318,29 +308,7 @@ export let TabPanel = defineComponent({ static: { type: Boolean, default: false }, unmount: { type: Boolean, default: true }, }, - render() { - let api = useTabsContext('TabPanel') - - let slot = { selected: this.selected } - let propsWeControl = { - ref: 'el', - id: this.id, - role: 'tabpanel', - 'aria-labelledby': api.tabs.value[this.myIndex]?.value?.id, - tabIndex: this.selected ? 0 : -1, - } - - return render({ - props: { ...this.$props, ...propsWeControl }, - slot, - attrs: this.$attrs, - slots: this.$slots, - features: Features.Static | Features.RenderStrategy, - visible: this.selected, - name: 'TabPanel', - }) - }, - setup() { + setup(props, { attrs, slots }) { let api = useTabsContext('TabPanel') let id = `headlessui-tabs-panel-${useId()}` @@ -352,6 +320,25 @@ export let TabPanel = defineComponent({ let myIndex = computed(() => api.panels.value.indexOf(panelRef)) let selected = computed(() => myIndex.value === api.selectedIndex.value) - return { id, el: panelRef, selected, myIndex } + return () => { + let slot = { selected: selected.value } + let propsWeControl = { + ref: panelRef, + id, + role: 'tabpanel', + 'aria-labelledby': api.tabs.value[myIndex.value]?.value?.id, + tabIndex: selected.value ? 0 : -1, + } + + return render({ + props: { ...props, ...propsWeControl }, + slot, + attrs, + slots, + features: Features.Static | Features.RenderStrategy, + visible: selected.value, + name: 'TabPanel', + }) + } }, }) diff --git a/packages/@headlessui-vue/src/components/transitions/transition.test.ts b/packages/@headlessui-vue/src/components/transitions/transition.test.ts index fad8025c74..ea01ade06b 100644 --- a/packages/@headlessui-vue/src/components/transitions/transition.test.ts +++ b/packages/@headlessui-vue/src/components/transitions/transition.test.ts @@ -1,4 +1,4 @@ -import { defineComponent, ref, onMounted } from 'vue' +import { defineComponent, ref, onMounted, ComponentOptionsWithoutProps } from 'vue' import { render, fireEvent } from '../../test-utils/vue-testing-library' import { suppressConsoleLogs } from '../../test-utils/suppress-console-logs' @@ -11,7 +11,7 @@ jest.mock('../../hooks/use-id') afterAll(() => jest.restoreAllMocks()) -function renderTemplate(input: string | Partial[0]>) { +function renderTemplate(input: string | ComponentOptionsWithoutProps) { let defaultComponents = { TransitionRoot, TransitionChild } if (typeof input === 'string') { @@ -58,9 +58,7 @@ it('should render without crashing', () => { it('should be possible to render a Transition without children', () => { renderTemplate({ - template: html` - - `, + template: html` `, }) expect(document.getElementsByClassName('transition')).not.toBeNull() }) @@ -91,12 +89,10 @@ describe('Setup API', () => { describe('shallow', () => { it('should render a div and its children by default', () => { let { container } = renderTemplate({ - template: html` - Children - `, + template: html`Children`, }) - expect(container.firstChild).toMatchInlineSnapshot(html` + expect(container.firstChild).toMatchInlineSnapshot(`
Children
@@ -106,9 +102,7 @@ describe('Setup API', () => { it('should passthrough all the props (that we do not use internally)', () => { let { container } = renderTemplate({ template: html` - - Children - + Children `, }) @@ -124,11 +118,7 @@ describe('Setup API', () => { it('should render another component if the `as` prop is used and its children by default', () => { let { container } = renderTemplate({ - template: html` - - Children - - `, + template: html` Children `, }) expect(container.firstChild).toMatchInlineSnapshot(` @@ -159,9 +149,7 @@ describe('Setup API', () => { it('should render nothing when the show prop is false', () => { let { container } = renderTemplate({ - template: html` - Children - `, + template: html` Children `, }) expect(container.firstChild).toMatchInlineSnapshot(``) @@ -169,11 +157,7 @@ describe('Setup API', () => { it('should be possible to change the underlying DOM tag', () => { let { container } = renderTemplate({ - template: html` - - Children - - `, + template: html` Children `, }) expect(container.firstChild).toMatchInlineSnapshot(` @@ -470,9 +454,7 @@ describe('Transitions', () => { Hello!
- + `, setup() { let show = ref(false) @@ -525,9 +507,7 @@ describe('Transitions', () => { Hello!
- + `, setup() { let show = ref(false) @@ -580,9 +560,7 @@ describe('Transitions', () => { Hello! - + `, setup() { let show = ref(false) @@ -630,9 +608,7 @@ describe('Transitions', () => { Hello! - + `, setup() { let show = ref(false) @@ -687,9 +663,7 @@ describe('Transitions', () => { Hello! - + `, setup() { let show = ref(true) @@ -753,9 +727,7 @@ describe('Transitions', () => { Hello! - + `, setup() { let show = ref(true) @@ -822,9 +794,7 @@ describe('Transitions', () => { Hello! - + `, setup() { let show = ref(false) @@ -918,9 +888,7 @@ describe('Transitions', () => { Hello! - + `, setup() { let show = ref(false) @@ -1021,9 +989,7 @@ describe('Transitions', () => { - + `, setup() { let show = ref(true) @@ -1113,9 +1079,7 @@ describe('Transitions', () => { - + `, setup() { let show = ref(true) @@ -1227,9 +1191,7 @@ describe('Events', () => { Hello! - + `, setup() { let show = ref(false) diff --git a/packages/@headlessui-vue/src/components/transitions/transition.ts b/packages/@headlessui-vue/src/components/transitions/transition.ts index baed2a359f..87748dc9b8 100644 --- a/packages/@headlessui-vue/src/components/transitions/transition.ts +++ b/packages/@headlessui-vue/src/components/transitions/transition.ts @@ -13,12 +13,13 @@ import { // Types InjectionKey, Ref, + ConcreteComponent, } from 'vue' import { useId } from '../../hooks/use-id' import { match } from '../../utils/match' -import { Features, render, RenderStrategy } from '../../utils/render' +import { Features, omit, render, RenderStrategy } from '../../utils/render' import { Reason, transition } from './utils/transition' import { dom } from '../../utils/dom' import { @@ -31,7 +32,7 @@ import { type ID = ReturnType function splitClasses(classes: string = '') { - return classes.split(' ').filter(className => className.trim().length > 1) + return classes.split(' ').filter((className) => className.trim().length > 1) } interface TransitionContextValues { @@ -151,54 +152,20 @@ export let TransitionChild = defineComponent({ beforeLeave: () => true, afterLeave: () => true, }, - render() { - if (this.renderAsRoot) { - return h( - TransitionRoot, - { - ...this.$props, - onBeforeEnter: () => this.$emit('beforeEnter'), - onAfterEnter: () => this.$emit('afterEnter'), - onBeforeLeave: () => this.$emit('beforeLeave'), - onAfterLeave: () => this.$emit('afterLeave'), - }, - this.$slots - ) - } - - let { - appear, - show, - - // Class names - enter, - enterFrom, - enterTo, - entered, - leave, - leaveFrom, - leaveTo, - ...rest - } = this.$props - - let propsWeControl = { ref: 'el' } - let passthroughProps = rest - - return render({ - props: { ...passthroughProps, ...propsWeControl }, - slot: {}, - slots: this.$slots, - attrs: this.$attrs, - features: TransitionChildRenderFeatures, - visible: this.state === TreeStates.Visible, - name: 'TransitionChild', - }) - }, - setup(props, { emit }) { + setup(props, { emit, attrs, slots }) { if (!hasTransitionContext() && hasOpenClosed()) { - return { - renderAsRoot: true, - } + return () => + h( + TransitionRoot, + { + ...props, + onBeforeEnter: () => emit('beforeEnter'), + onAfterEnter: () => emit('afterEnter'), + onBeforeLeave: () => emit('beforeLeave'), + onAfterLeave: () => emit('afterLeave'), + }, + slots + ) } let container = ref(null) @@ -292,7 +259,7 @@ export let TransitionChild = defineComponent({ enterFromClasses, enterToClasses, enteredClasses, - reason => { + (reason) => { isTransitioning.value = false if (reason === Reason.Finished) emit('afterEnter') } @@ -303,7 +270,7 @@ export let TransitionChild = defineComponent({ leaveFromClasses, leaveToClasses, enteredClasses, - reason => { + (reason) => { isTransitioning.value = false if (reason !== Reason.Finished) return @@ -341,12 +308,43 @@ export let TransitionChild = defineComponent({ ) ) - return { el: container, renderAsRoot: false, state } + return () => { + let { + appear, + show, + + // Class names + enter, + enterFrom, + enterTo, + entered, + leave, + leaveFrom, + leaveTo, + ...rest + } = props + + let propsWeControl = { ref: container } + let passthroughProps = rest + + return render({ + props: { ...passthroughProps, ...propsWeControl }, + slot: {}, + slots, + attrs, + features: TransitionChildRenderFeatures, + visible: state.value === TreeStates.Visible, + name: 'TransitionChild', + }) + } }, }) // --- +// This exists to work around typescript circular inference problem +let _TransitionChild = TransitionChild as ConcreteComponent + export let TransitionRoot = defineComponent({ inheritAttrs: false, props: { @@ -368,41 +366,7 @@ export let TransitionRoot = defineComponent({ beforeLeave: () => true, afterLeave: () => true, }, - render() { - let { show, appear, unmount, ...passThroughProps } = this.$props - let sharedProps = { unmount } - - return render({ - props: { - ...sharedProps, - as: 'template', - }, - slot: {}, - slots: { - ...this.$slots, - default: () => [ - h( - TransitionChild, - { - onBeforeEnter: () => this.$emit('beforeEnter'), - onAfterEnter: () => this.$emit('afterEnter'), - onBeforeLeave: () => this.$emit('beforeLeave'), - onAfterLeave: () => this.$emit('afterLeave'), - ...this.$attrs, - ...sharedProps, - ...passThroughProps, - }, - this.$slots.default - ), - ], - }, - attrs: {}, - features: TransitionChildRenderFeatures, - visible: this.state === TreeStates.Visible, - name: 'Transition', - }) - }, - setup(props) { + setup(props, { emit, attrs, slots }) { let usesOpenClosedState = useOpenClosed() let show = computed(() => { @@ -449,6 +413,39 @@ export let TransitionRoot = defineComponent({ provide(NestingContext, nestingBag) provide(TransitionContext, transitionBag) - return { state, show } + return () => { + let passThroughProps = omit(props, ['show', 'appear', 'unmount']) + let sharedProps = { unmount: props.unmount } + + return render({ + props: { + ...sharedProps, + as: 'template', + }, + slot: {}, + slots: { + ...slots, + default: () => [ + h( + _TransitionChild, + { + onBeforeEnter: () => emit('beforeEnter'), + onAfterEnter: () => emit('afterEnter'), + onBeforeLeave: () => emit('beforeLeave'), + onAfterLeave: () => emit('afterLeave'), + ...attrs, + ...sharedProps, + ...passThroughProps, + }, + slots.default + ), + ], + }, + attrs: {}, + features: TransitionChildRenderFeatures, + visible: state.value === TreeStates.Visible, + name: 'Transition', + }) + } }, }) diff --git a/packages/@headlessui-vue/src/components/transitions/utils/transition.test.ts b/packages/@headlessui-vue/src/components/transitions/utils/transition.test.ts index 9918716179..58cd91a0aa 100644 --- a/packages/@headlessui-vue/src/components/transitions/utils/transition.test.ts +++ b/packages/@headlessui-vue/src/components/transitions/utils/transition.test.ts @@ -17,7 +17,7 @@ it('should be possible to transition', async () => { d.add( reportChanges( () => document.body.innerHTML, - content => { + (content) => { snapshots.push({ content, recordedAt: process.hrtime.bigint(), @@ -26,11 +26,11 @@ it('should be possible to transition', async () => { ) ) - await new Promise(resolve => { + await new Promise((resolve) => { transition(element, ['enter'], ['enterFrom'], ['enterTo'], ['entered'], resolve) }) - await new Promise(resolve => d.nextFrame(resolve)) + await new Promise((resolve) => d.nextFrame(resolve)) // Initial render: expect(snapshots[0].content).toEqual('
') @@ -61,7 +61,7 @@ it('should wait the correct amount of time to finish a transition', async () => d.add( reportChanges( () => document.body.innerHTML, - content => { + (content) => { snapshots.push({ content, recordedAt: process.hrtime.bigint(), @@ -70,11 +70,11 @@ it('should wait the correct amount of time to finish a transition', async () => ) ) - let reason = await new Promise(resolve => { + let reason = await new Promise((resolve) => { transition(element, ['enter'], ['enterFrom'], ['enterTo'], ['entered'], resolve) }) - await new Promise(resolve => d.nextFrame(resolve)) + await new Promise((resolve) => d.nextFrame(resolve)) expect(reason).toBe(Reason.Finished) // Initial render: @@ -118,7 +118,7 @@ it('should keep the delay time into account', async () => { d.add( reportChanges( () => document.body.innerHTML, - content => { + (content) => { snapshots.push({ content, recordedAt: process.hrtime.bigint(), @@ -127,11 +127,11 @@ it('should keep the delay time into account', async () => { ) ) - let reason = await new Promise(resolve => { + let reason = await new Promise((resolve) => { transition(element, ['enter'], ['enterFrom'], ['enterTo'], ['entered'], resolve) }) - await new Promise(resolve => d.nextFrame(resolve)) + await new Promise((resolve) => d.nextFrame(resolve)) expect(reason).toBe(Reason.Finished) let estimatedDuration = Number( @@ -161,7 +161,7 @@ it('should be possible to cancel a transition at any time', async () => { d.add( reportChanges( () => document.body.innerHTML, - content => { + (content) => { let recordedAt = process.hrtime.bigint() let total = snapshots.length @@ -178,16 +178,16 @@ it('should be possible to cancel a transition at any time', async () => { expect.assertions(2) // Setup the transition - let cancel = transition(element, ['enter'], ['enterFrom'], ['enterTo'], ['entered'], reason => { + let cancel = transition(element, ['enter'], ['enterFrom'], ['enterTo'], ['entered'], (reason) => { expect(reason).toBe(Reason.Cancelled) }) // Wait for a bit - await new Promise(resolve => setTimeout(resolve, 20)) + await new Promise((resolve) => setTimeout(resolve, 20)) // Cancel the transition cancel() - await new Promise(resolve => d.nextFrame(resolve)) + await new Promise((resolve) => d.nextFrame(resolve)) - expect(snapshots.map(snapshot => snapshot.content).join('\n')).not.toContain('enterTo') + expect(snapshots.map((snapshot) => snapshot.content).join('\n')).not.toContain('enterTo') }) diff --git a/packages/@headlessui-vue/src/components/transitions/utils/transition.ts b/packages/@headlessui-vue/src/components/transitions/utils/transition.ts index 8382141da9..008a01375a 100644 --- a/packages/@headlessui-vue/src/components/transitions/utils/transition.ts +++ b/packages/@headlessui-vue/src/components/transitions/utils/transition.ts @@ -22,13 +22,13 @@ function waitForTransition(node: HTMLElement, done: (reason: Reason) => void) { // Safari returns a comma separated list of values, so let's sort them and take the highest value. let { transitionDuration, transitionDelay } = getComputedStyle(node) - let [durationMs, delaysMs] = [transitionDuration, transitionDelay].map(value => { + let [durationMs, delaysMs] = [transitionDuration, transitionDelay].map((value) => { let [resolvedValue = 0] = value .split(',') // Remove falseys we can't work with .filter(Boolean) // Values are returned as `0.3s` or `75ms` - .map(v => (v.includes('ms') ? parseFloat(v) : parseFloat(v) * 1000)) + .map((v) => (v.includes('ms') ? parseFloat(v) : parseFloat(v) * 1000)) .sort((a, z) => z - a) return resolvedValue @@ -72,7 +72,7 @@ export function transition( addClasses(node, ...to) d.add( - waitForTransition(node, reason => { + waitForTransition(node, (reason) => { removeClasses(node, ...to, ...base) addClasses(node, ...entered) return _done(reason) diff --git a/packages/@headlessui-vue/src/hooks/use-focus-trap.ts b/packages/@headlessui-vue/src/hooks/use-focus-trap.ts index e5a070e721..034b64760e 100644 --- a/packages/@headlessui-vue/src/hooks/use-focus-trap.ts +++ b/packages/@headlessui-vue/src/hooks/use-focus-trap.ts @@ -75,7 +75,7 @@ export function useFocusTrap( onUnmounted(restore) // Handle Tab & Shift+Tab keyboard events - useWindowEvent('keydown', event => { + useWindowEvent('keydown', (event) => { if (!enabled.value) return if (event.key !== Keys.Tab) return if (!document.activeElement) return @@ -99,7 +99,7 @@ export function useFocusTrap( // Prevent programmatically escaping useWindowEvent( 'focus', - event => { + (event) => { if (!enabled.value) return if (containers.value.size !== 1) return diff --git a/packages/@headlessui-vue/src/hooks/use-inert-others.test.ts b/packages/@headlessui-vue/src/hooks/use-inert-others.test.ts index 46b5ed6643..3b82253a55 100644 --- a/packages/@headlessui-vue/src/hooks/use-inert-others.test.ts +++ b/packages/@headlessui-vue/src/hooks/use-inert-others.test.ts @@ -1,4 +1,4 @@ -import { defineComponent, ref, nextTick } from 'vue' +import { defineComponent, ref, nextTick, ComponentOptionsWithoutProps } from 'vue' import { render } from '../test-utils/vue-testing-library' import { useInertOthers } from './use-inert-others' @@ -14,7 +14,7 @@ beforeAll(() => { afterAll(() => jest.restoreAllMocks()) -function renderTemplate(input: string | Partial[0]>) { +function renderTemplate(input: string | ComponentOptionsWithoutProps) { let defaultComponents = {} if (typeof input === 'string') { @@ -35,16 +35,12 @@ function renderTemplate(input: string | Partialbefore
- `, + template: html`
before
`, }) let After = defineComponent({ name: 'After', - template: html` -
after
- `, + template: html`
after
`, }) it('should be possible to inert other elements', async () => { diff --git a/packages/@headlessui-vue/src/hooks/use-inert-others.ts b/packages/@headlessui-vue/src/hooks/use-inert-others.ts index ae85338561..5d28bf7d2a 100644 --- a/packages/@headlessui-vue/src/hooks/use-inert-others.ts +++ b/packages/@headlessui-vue/src/hooks/use-inert-others.ts @@ -32,7 +32,7 @@ export function useInertOthers( container: Ref, enabled: Ref = ref(true) ) { - watchEffect(onInvalidate => { + watchEffect((onInvalidate) => { if (!enabled.value) return if (!container.value) return @@ -50,7 +50,7 @@ export function useInertOthers( } // Collect direct children of the body - document.querySelectorAll(CHILDREN_SELECTOR).forEach(child => { + document.querySelectorAll(CHILDREN_SELECTOR).forEach((child) => { if (!(child instanceof HTMLElement)) return // Skip non-HTMLElements // Skip the interactables, and the parents of the interactables @@ -79,7 +79,7 @@ export function useInertOthers( // will become inert as well. if (interactables.size > 0) { // Collect direct children of the body - document.querySelectorAll(CHILDREN_SELECTOR).forEach(child => { + document.querySelectorAll(CHILDREN_SELECTOR).forEach((child) => { if (!(child instanceof HTMLElement)) return // Skip non-HTMLElements // Skip already inert parents diff --git a/packages/@headlessui-vue/src/hooks/use-tree-walker.ts b/packages/@headlessui-vue/src/hooks/use-tree-walker.ts index 9b216e337b..27f45bd5a2 100644 --- a/packages/@headlessui-vue/src/hooks/use-tree-walker.ts +++ b/packages/@headlessui-vue/src/hooks/use-tree-walker.ts @@ -24,6 +24,7 @@ export function useTreeWalker({ if (enabled !== undefined && !enabled.value) return let acceptNode = Object.assign((node: HTMLElement) => accept(node), { acceptNode: accept }) + // @ts-expect-error This `false` is a simple small fix for older browsers let walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, acceptNode, false) while (walker.nextNode()) walk(walker.currentNode as HTMLElement) diff --git a/packages/@headlessui-vue/src/hooks/use-window-event.ts b/packages/@headlessui-vue/src/hooks/use-window-event.ts index 8929c0dd89..987802e92e 100644 --- a/packages/@headlessui-vue/src/hooks/use-window-event.ts +++ b/packages/@headlessui-vue/src/hooks/use-window-event.ts @@ -7,7 +7,7 @@ export function useWindowEvent( ) { if (typeof window === 'undefined') return - watchEffect(onInvalidate => { + watchEffect((onInvalidate) => { window.addEventListener(type, listener, options) onInvalidate(() => { diff --git a/packages/@headlessui-vue/src/index.test.ts b/packages/@headlessui-vue/src/index.test.ts index 97ddbee3e8..d8d8fac3e0 100644 --- a/packages/@headlessui-vue/src/index.test.ts +++ b/packages/@headlessui-vue/src/index.test.ts @@ -6,6 +6,14 @@ import * as HeadlessUI from './index' */ it('should expose the correct components', () => { expect(Object.keys(HeadlessUI)).toEqual([ + // Combobox + 'Combobox', + 'ComboboxLabel', + 'ComboboxButton', + 'ComboboxInput', + 'ComboboxOptions', + 'ComboboxOption', + // Dialog 'Dialog', 'DialogOverlay', diff --git a/packages/@headlessui-vue/src/index.ts b/packages/@headlessui-vue/src/index.ts index 2ef29db23c..2ba6c32e78 100644 --- a/packages/@headlessui-vue/src/index.ts +++ b/packages/@headlessui-vue/src/index.ts @@ -1,3 +1,4 @@ +export * from './components/combobox/combobox' export * from './components/dialog/dialog' export * from './components/disclosure/disclosure' export * from './components/focus-trap/focus-trap' diff --git a/packages/@headlessui-vue/src/internal/stack-context.ts b/packages/@headlessui-vue/src/internal/stack-context.ts index 1f468469c3..595a8756fd 100644 --- a/packages/@headlessui-vue/src/internal/stack-context.ts +++ b/packages/@headlessui-vue/src/internal/stack-context.ts @@ -24,7 +24,7 @@ export function useStackContext() { export function useElemenStack(element: Ref | null) { let notify = useStackContext() - watchEffect(onInvalidate => { + watchEffect((onInvalidate) => { let domElement = element?.value if (!domElement) return diff --git a/packages/@headlessui-vue/src/test-utils/accessibility-assertions.ts b/packages/@headlessui-vue/src/test-utils/accessibility-assertions.ts index 1fb40a1f39..d2ef0479ed 100644 --- a/packages/@headlessui-vue/src/test-utils/accessibility-assertions.ts +++ b/packages/@headlessui-vue/src/test-utils/accessibility-assertions.ts @@ -91,7 +91,7 @@ export function assertMenuButton( expect(button).toHaveAttribute(attributeName, options.attributes[attributeName]) } } catch (err) { - Error.captureStackTrace(err, assertMenuButton) + if (err instanceof Error) Error.captureStackTrace(err, assertMenuButton) throw err } } @@ -105,7 +105,7 @@ export function assertMenuButtonLinkedWithMenu(button = getMenuButton(), menu = expect(button).toHaveAttribute('aria-controls', menu.getAttribute('id')) expect(menu).toHaveAttribute('aria-labelledby', button.getAttribute('id')) } catch (err) { - Error.captureStackTrace(err, assertMenuButtonLinkedWithMenu) + if (err instanceof Error) Error.captureStackTrace(err, assertMenuButtonLinkedWithMenu) throw err } } @@ -118,7 +118,7 @@ export function assertMenuLinkedWithMenuItem(item: HTMLElement | null, menu = ge // Ensure link between menu & menu item is correct expect(menu).toHaveAttribute('aria-activedescendant', item.getAttribute('id')) } catch (err) { - Error.captureStackTrace(err, assertMenuLinkedWithMenuItem) + if (err instanceof Error) Error.captureStackTrace(err, assertMenuLinkedWithMenuItem) throw err } } @@ -130,7 +130,7 @@ export function assertNoActiveMenuItem(menu = getMenu()) { // Ensure we don't have an active menu expect(menu).not.toHaveAttribute('aria-activedescendant') } catch (err) { - Error.captureStackTrace(err, assertNoActiveMenuItem) + if (err instanceof Error) Error.captureStackTrace(err, assertNoActiveMenuItem) throw err } } @@ -183,7 +183,7 @@ export function assertMenu( assertNever(options.state) } } catch (err) { - Error.captureStackTrace(err, assertMenu) + if (err instanceof Error) Error.captureStackTrace(err, assertMenu) throw err } } @@ -214,7 +214,393 @@ export function assertMenuItem( } } } catch (err) { - Error.captureStackTrace(err, assertMenuItem) + if (err instanceof Error) Error.captureStackTrace(err, assertMenuItem) + throw err + } +} + +// --- + +export function getComboboxLabel(): HTMLElement | null { + return document.querySelector('label,[id^="headlessui-combobox-label"]') +} + +export function getComboboxButton(): HTMLElement | null { + return document.querySelector('button,[role="button"],[id^="headlessui-combobox-button-"]') +} + +export function getComboboxButtons(): HTMLElement[] { + return Array.from(document.querySelectorAll('button,[role="button"]')) +} + +export function getComboboxInput(): HTMLInputElement | null { + return document.querySelector('[role="combobox"]') +} + +export function getCombobox(): HTMLElement | null { + return document.querySelector('[role="listbox"]') +} + +export function getComboboxInputs(): HTMLElement[] { + return Array.from(document.querySelectorAll('[role="combobox"]')) +} + +export function getComboboxes(): HTMLElement[] { + return Array.from(document.querySelectorAll('[role="listbox"]')) +} + +export function getComboboxOptions(): HTMLElement[] { + return Array.from(document.querySelectorAll('[role="option"]')) +} + +// --- + +export enum ComboboxState { + /** The combobox is visible to the user. */ + Visible, + + /** The combobox is **not** visible to the user. It's still in the DOM, but it is hidden. */ + InvisibleHidden, + + /** The combobox is **not** visible to the user. It's not in the DOM, it is unmounted. */ + InvisibleUnmounted, +} + +export function assertCombobox( + options: { + attributes?: Record + textContent?: string + state: ComboboxState + orientation?: 'horizontal' | 'vertical' + }, + combobox = getComboboxInput() +) { + let { orientation = 'vertical' } = options + + try { + switch (options.state) { + case ComboboxState.InvisibleHidden: + if (combobox === null) return expect(combobox).not.toBe(null) + + assertHidden(combobox) + + expect(combobox).toHaveAttribute('aria-labelledby') + expect(combobox).toHaveAttribute('aria-orientation', orientation) + expect(combobox).toHaveAttribute('role', 'combobox') + + if (options.textContent) expect(combobox).toHaveTextContent(options.textContent) + + for (let attributeName in options.attributes) { + expect(combobox).toHaveAttribute(attributeName, options.attributes[attributeName]) + } + break + + case ComboboxState.Visible: + if (combobox === null) return expect(combobox).not.toBe(null) + + assertVisible(combobox) + + expect(combobox).toHaveAttribute('aria-labelledby') + expect(combobox).toHaveAttribute('aria-orientation', orientation) + expect(combobox).toHaveAttribute('role', 'combobox') + + if (options.textContent) expect(combobox).toHaveTextContent(options.textContent) + + for (let attributeName in options.attributes) { + expect(combobox).toHaveAttribute(attributeName, options.attributes[attributeName]) + } + break + + case ComboboxState.InvisibleUnmounted: + expect(combobox).toBe(null) + break + + default: + assertNever(options.state) + } + } catch (err) { + if (err instanceof Error) Error.captureStackTrace(err, assertCombobox) + throw err + } +} + +export function assertComboboxList( + options: { + attributes?: Record + textContent?: string + state: ComboboxState + orientation?: 'horizontal' | 'vertical' + }, + listbox = getCombobox() +) { + let { orientation = 'vertical' } = options + + try { + switch (options.state) { + case ComboboxState.InvisibleHidden: + if (listbox === null) return expect(listbox).not.toBe(null) + + assertHidden(listbox) + + expect(listbox).toHaveAttribute('aria-labelledby') + expect(listbox).toHaveAttribute('aria-orientation', orientation) + expect(listbox).toHaveAttribute('role', 'listbox') + + if (options.textContent) expect(listbox).toHaveTextContent(options.textContent) + + for (let attributeName in options.attributes) { + expect(listbox).toHaveAttribute(attributeName, options.attributes[attributeName]) + } + break + + case ComboboxState.Visible: + if (listbox === null) return expect(listbox).not.toBe(null) + + assertVisible(listbox) + + expect(listbox).toHaveAttribute('aria-labelledby') + expect(listbox).toHaveAttribute('aria-orientation', orientation) + expect(listbox).toHaveAttribute('role', 'listbox') + + if (options.textContent) expect(listbox).toHaveTextContent(options.textContent) + + for (let attributeName in options.attributes) { + expect(listbox).toHaveAttribute(attributeName, options.attributes[attributeName]) + } + break + + case ComboboxState.InvisibleUnmounted: + expect(listbox).toBe(null) + break + + default: + assertNever(options.state) + } + } catch (err) { + if (err instanceof Error) Error.captureStackTrace(err, assertCombobox) + throw err + } +} + +export function assertComboboxButton( + options: { + attributes?: Record + textContent?: string + state: ComboboxState + }, + button = getComboboxButton() +) { + try { + if (button === null) return expect(button).not.toBe(null) + + // Ensure menu button have these properties + expect(button).toHaveAttribute('id') + expect(button).toHaveAttribute('aria-haspopup') + + switch (options.state) { + case ComboboxState.Visible: + expect(button).toHaveAttribute('aria-controls') + expect(button).toHaveAttribute('aria-expanded', 'true') + break + + case ComboboxState.InvisibleHidden: + expect(button).toHaveAttribute('aria-controls') + if (button.hasAttribute('disabled')) { + expect(button).not.toHaveAttribute('aria-expanded') + } else { + expect(button).toHaveAttribute('aria-expanded', 'false') + } + break + + case ComboboxState.InvisibleUnmounted: + expect(button).not.toHaveAttribute('aria-controls') + if (button.hasAttribute('disabled')) { + expect(button).not.toHaveAttribute('aria-expanded') + } else { + expect(button).toHaveAttribute('aria-expanded', 'false') + } + break + + default: + assertNever(options.state) + } + + if (options.textContent) { + expect(button).toHaveTextContent(options.textContent) + } + + // Ensure menu button has the following attributes + for (let attributeName in options.attributes) { + expect(button).toHaveAttribute(attributeName, options.attributes[attributeName]) + } + } catch (err) { + if (err instanceof Error) Error.captureStackTrace(err, assertComboboxButton) + throw err + } +} + +export function assertComboboxLabel( + options: { + attributes?: Record + tag?: string + textContent?: string + }, + label = getComboboxLabel() +) { + try { + if (label === null) return expect(label).not.toBe(null) + + // Ensure menu button have these properties + expect(label).toHaveAttribute('id') + + if (options.textContent) { + expect(label).toHaveTextContent(options.textContent) + } + + if (options.tag) { + expect(label.tagName.toLowerCase()).toBe(options.tag) + } + + // Ensure menu button has the following attributes + for (let attributeName in options.attributes) { + expect(label).toHaveAttribute(attributeName, options.attributes[attributeName]) + } + } catch (err) { + if (err instanceof Error) Error.captureStackTrace(err, assertComboboxLabel) + throw err + } +} + +export function assertComboboxButtonLinkedWithCombobox( + button = getComboboxButton(), + combobox = getCombobox() +) { + try { + if (button === null) return expect(button).not.toBe(null) + if (combobox === null) return expect(combobox).not.toBe(null) + + // Ensure link between button & combobox is correct + expect(button).toHaveAttribute('aria-controls', combobox.getAttribute('id')) + expect(combobox).toHaveAttribute('aria-labelledby', button.getAttribute('id')) + } catch (err) { + if (err instanceof Error) Error.captureStackTrace(err, assertComboboxButtonLinkedWithCombobox) + throw err + } +} + +export function assertComboboxLabelLinkedWithCombobox( + label = getComboboxLabel(), + combobox = getComboboxInput() +) { + try { + if (label === null) return expect(label).not.toBe(null) + if (combobox === null) return expect(combobox).not.toBe(null) + + expect(combobox).toHaveAttribute('aria-labelledby', label.getAttribute('id')) + } catch (err) { + if (err instanceof Error) Error.captureStackTrace(err, assertComboboxLabelLinkedWithCombobox) + throw err + } +} + +export function assertComboboxButtonLinkedWithComboboxLabel( + button = getComboboxButton(), + label = getComboboxLabel() +) { + try { + if (button === null) return expect(button).not.toBe(null) + if (label === null) return expect(label).not.toBe(null) + + // Ensure link between button & label is correct + expect(button).toHaveAttribute('aria-labelledby', `${label.id} ${button.id}`) + } catch (err) { + if (err instanceof Error) + Error.captureStackTrace(err, assertComboboxButtonLinkedWithComboboxLabel) + throw err + } +} + +export function assertActiveComboboxOption( + item: HTMLElement | null, + combobox = getComboboxInput() +) { + try { + if (combobox === null) return expect(combobox).not.toBe(null) + if (item === null) return expect(item).not.toBe(null) + + // Ensure link between combobox & combobox item is correct + expect(combobox).toHaveAttribute('aria-activedescendant', item.getAttribute('id')) + } catch (err) { + if (err instanceof Error) Error.captureStackTrace(err, assertActiveComboboxOption) + throw err + } +} + +export function assertNoActiveComboboxOption(combobox = getComboboxInput()) { + try { + if (combobox === null) return expect(combobox).not.toBe(null) + + // Ensure we don't have an active combobox + expect(combobox).not.toHaveAttribute('aria-activedescendant') + } catch (err) { + if (err instanceof Error) Error.captureStackTrace(err, assertNoActiveComboboxOption) + throw err + } +} + +export function assertNoSelectedComboboxOption(items = getComboboxOptions()) { + try { + for (let item of items) expect(item).not.toHaveAttribute('aria-selected') + } catch (err) { + if (err instanceof Error) Error.captureStackTrace(err, assertNoSelectedComboboxOption) + throw err + } +} + +export function assertComboboxOption( + item: HTMLElement | null, + options?: { + tag?: string + attributes?: Record + selected?: boolean + } +) { + try { + if (item === null) return expect(item).not.toBe(null) + + // Check that some attributes exists, doesn't really matter what the values are at this point in + // time, we just require them. + expect(item).toHaveAttribute('id') + + // Check that we have the correct values for certain attributes + expect(item).toHaveAttribute('role', 'option') + if (!item.getAttribute('aria-disabled')) expect(item).toHaveAttribute('tabindex', '-1') + + // Ensure combobox button has the following attributes + if (!options) return + + for (let attributeName in options.attributes) { + expect(item).toHaveAttribute(attributeName, options.attributes[attributeName]) + } + + if (options.tag) { + expect(item.tagName.toLowerCase()).toBe(options.tag) + } + + if (options.selected != null) { + switch (options.selected) { + case true: + return expect(item).toHaveAttribute('aria-selected', 'true') + + case false: + return expect(item).not.toHaveAttribute('aria-selected') + + default: + assertNever(options.selected) + } + } + } catch (err) { + if (err instanceof Error) Error.captureStackTrace(err, assertComboboxOption) throw err } } @@ -311,7 +697,7 @@ export function assertListbox( assertNever(options.state) } } catch (err) { - Error.captureStackTrace(err, assertListbox) + if (err instanceof Error) Error.captureStackTrace(err, assertListbox) throw err } } @@ -368,7 +754,7 @@ export function assertListboxButton( expect(button).toHaveAttribute(attributeName, options.attributes[attributeName]) } } catch (err) { - Error.captureStackTrace(err, assertListboxButton) + if (err instanceof Error) Error.captureStackTrace(err, assertListboxButton) throw err } } @@ -400,7 +786,7 @@ export function assertListboxLabel( expect(label).toHaveAttribute(attributeName, options.attributes[attributeName]) } } catch (err) { - Error.captureStackTrace(err, assertListboxLabel) + if (err instanceof Error) Error.captureStackTrace(err, assertListboxLabel) throw err } } @@ -417,7 +803,7 @@ export function assertListboxButtonLinkedWithListbox( expect(button).toHaveAttribute('aria-controls', listbox.getAttribute('id')) expect(listbox).toHaveAttribute('aria-labelledby', button.getAttribute('id')) } catch (err) { - Error.captureStackTrace(err, assertListboxButtonLinkedWithListbox) + if (err instanceof Error) Error.captureStackTrace(err, assertListboxButtonLinkedWithListbox) throw err } } @@ -432,7 +818,7 @@ export function assertListboxLabelLinkedWithListbox( expect(listbox).toHaveAttribute('aria-labelledby', label.getAttribute('id')) } catch (err) { - Error.captureStackTrace(err, assertListboxLabelLinkedWithListbox) + if (err instanceof Error) Error.captureStackTrace(err, assertListboxLabelLinkedWithListbox) throw err } } @@ -448,7 +834,8 @@ export function assertListboxButtonLinkedWithListboxLabel( // Ensure link between button & label is correct expect(button).toHaveAttribute('aria-labelledby', `${label.id} ${button.id}`) } catch (err) { - Error.captureStackTrace(err, assertListboxButtonLinkedWithListboxLabel) + if (err instanceof Error) + Error.captureStackTrace(err, assertListboxButtonLinkedWithListboxLabel) throw err } } @@ -461,7 +848,7 @@ export function assertActiveListboxOption(item: HTMLElement | null, listbox = ge // Ensure link between listbox & listbox item is correct expect(listbox).toHaveAttribute('aria-activedescendant', item.getAttribute('id')) } catch (err) { - Error.captureStackTrace(err, assertActiveListboxOption) + if (err instanceof Error) Error.captureStackTrace(err, assertActiveListboxOption) throw err } } @@ -473,7 +860,7 @@ export function assertNoActiveListboxOption(listbox = getListbox()) { // Ensure we don't have an active listbox expect(listbox).not.toHaveAttribute('aria-activedescendant') } catch (err) { - Error.captureStackTrace(err, assertNoActiveListboxOption) + if (err instanceof Error) Error.captureStackTrace(err, assertNoActiveListboxOption) throw err } } @@ -482,7 +869,7 @@ export function assertNoSelectedListboxOption(items = getListboxOptions()) { try { for (let item of items) expect(item).not.toHaveAttribute('aria-selected') } catch (err) { - Error.captureStackTrace(err, assertNoSelectedListboxOption) + if (err instanceof Error) Error.captureStackTrace(err, assertNoSelectedListboxOption) throw err } } @@ -530,7 +917,7 @@ export function assertListboxOption( } } } catch (err) { - Error.captureStackTrace(err, assertListboxOption) + if (err instanceof Error) Error.captureStackTrace(err, assertListboxOption) throw err } } @@ -597,7 +984,7 @@ export function assertSwitch( assertNever(options.state) } } catch (err) { - Error.captureStackTrace(err, assertSwitch) + if (err instanceof Error) Error.captureStackTrace(err, assertSwitch) throw err } } @@ -678,7 +1065,7 @@ export function assertDisclosureButton( expect(button).toHaveAttribute(attributeName, options.attributes[attributeName]) } } catch (err) { - Error.captureStackTrace(err, assertDisclosureButton) + if (err instanceof Error) Error.captureStackTrace(err, assertDisclosureButton) throw err } } @@ -725,7 +1112,7 @@ export function assertDisclosurePanel( assertNever(options.state) } } catch (err) { - Error.captureStackTrace(err, assertDisclosurePanel) + if (err instanceof Error) Error.captureStackTrace(err, assertDisclosurePanel) throw err } } @@ -810,7 +1197,7 @@ export function assertPopoverButton( expect(button).toHaveAttribute(attributeName, options.attributes[attributeName]) } } catch (err) { - Error.captureStackTrace(err, assertPopoverButton) + if (err instanceof Error) Error.captureStackTrace(err, assertPopoverButton) throw err } } @@ -857,7 +1244,7 @@ export function assertPopoverPanel( assertNever(options.state) } } catch (err) { - Error.captureStackTrace(err, assertPopoverPanel) + if (err instanceof Error) Error.captureStackTrace(err, assertPopoverPanel) throw err } } @@ -869,7 +1256,7 @@ export function assertLabelValue(element: HTMLElement | null, value: string) { if (element.hasAttribute('aria-labelledby')) { let ids = element.getAttribute('aria-labelledby')!.split(' ') - expect(ids.map(id => document.getElementById(id)?.textContent).join(' ')).toEqual(value) + expect(ids.map((id) => document.getElementById(id)?.textContent).join(' ')).toEqual(value) return } @@ -984,7 +1371,7 @@ export function assertDialog( assertNever(options.state) } } catch (err) { - Error.captureStackTrace(err, assertDialog) + if (err instanceof Error) Error.captureStackTrace(err, assertDialog) throw err } } @@ -1040,7 +1427,7 @@ export function assertDialogTitle( assertNever(options.state) } } catch (err) { - Error.captureStackTrace(err, assertDialogTitle) + if (err instanceof Error) Error.captureStackTrace(err, assertDialogTitle) throw err } } @@ -1096,7 +1483,7 @@ export function assertDialogDescription( assertNever(options.state) } } catch (err) { - Error.captureStackTrace(err, assertDialogDescription) + if (err instanceof Error) Error.captureStackTrace(err, assertDialogDescription) throw err } } @@ -1143,7 +1530,7 @@ export function assertDialogOverlay( assertNever(options.state) } } catch (err) { - Error.captureStackTrace(err, assertDialogOverlay) + if (err instanceof Error) Error.captureStackTrace(err, assertDialogOverlay) throw err } } @@ -1185,7 +1572,7 @@ export function assertRadioGroupLabel( expect(label).toHaveAttribute(attributeName, options.attributes[attributeName]) } } catch (err) { - Error.captureStackTrace(err, assertRadioGroupLabel) + if (err instanceof Error) Error.captureStackTrace(err, assertRadioGroupLabel) throw err } } @@ -1225,7 +1612,7 @@ export function assertTabs( expect(list).toHaveAttribute('aria-orientation', orientation) let activeTab = Array.from(list.querySelectorAll('[id^="headlessui-tabs-tab-"]'))[active] - let activePanel = panels.find(panel => panel.id === activeTab.getAttribute('aria-controls')) + let activePanel = panels.find((panel) => panel.id === activeTab.getAttribute('aria-controls')) for (let tab of tabs) { expect(tab).toHaveAttribute('id') @@ -1267,7 +1654,7 @@ export function assertTabs( } } } catch (err) { - Error.captureStackTrace(err, assertTabs) + if (err instanceof Error) Error.captureStackTrace(err, assertTabs) throw err } } @@ -1287,7 +1674,7 @@ export function assertActiveElement(element: HTMLElement | null) { expect(document.activeElement?.outerHTML).toBe(element.outerHTML) } } catch (err) { - Error.captureStackTrace(err, assertActiveElement) + if (err instanceof Error) Error.captureStackTrace(err, assertActiveElement) throw err } } @@ -1297,7 +1684,7 @@ export function assertContainsActiveElement(element: HTMLElement | null) { if (element === null) return expect(element).not.toBe(null) expect(element.contains(document.activeElement)).toBe(true) } catch (err) { - Error.captureStackTrace(err, assertContainsActiveElement) + if (err instanceof Error) Error.captureStackTrace(err, assertContainsActiveElement) throw err } } @@ -1311,7 +1698,7 @@ export function assertHidden(element: HTMLElement | null) { expect(element).toHaveAttribute('hidden') expect(element).toHaveStyle({ display: 'none' }) } catch (err) { - Error.captureStackTrace(err, assertHidden) + if (err instanceof Error) Error.captureStackTrace(err, assertHidden) throw err } } @@ -1323,7 +1710,7 @@ export function assertVisible(element: HTMLElement | null) { expect(element).not.toHaveAttribute('hidden') expect(element).not.toHaveStyle({ display: 'none' }) } catch (err) { - Error.captureStackTrace(err, assertVisible) + if (err instanceof Error) Error.captureStackTrace(err, assertVisible) throw err } } @@ -1336,7 +1723,7 @@ export function assertFocusable(element: HTMLElement | null) { expect(isFocusableElement(element, FocusableMode.Strict)).toBe(true) } catch (err) { - Error.captureStackTrace(err, assertFocusable) + if (err instanceof Error) Error.captureStackTrace(err, assertFocusable) throw err } } @@ -1347,7 +1734,7 @@ export function assertNotFocusable(element: HTMLElement | null) { expect(isFocusableElement(element, FocusableMode.Strict)).toBe(false) } catch (err) { - Error.captureStackTrace(err, assertNotFocusable) + if (err instanceof Error) Error.captureStackTrace(err, assertNotFocusable) throw err } } diff --git a/packages/@headlessui-vue/src/test-utils/execute-timeline.ts b/packages/@headlessui-vue/src/test-utils/execute-timeline.ts index 0fbec32088..5e9f9c7d08 100644 --- a/packages/@headlessui-vue/src/test-utils/execute-timeline.ts +++ b/packages/@headlessui-vue/src/test-utils/execute-timeline.ts @@ -18,7 +18,7 @@ function redentSnapshot(input: string) { return input .split('\n') - .map(line => + .map((line) => line.trim() === '---' ? line : line.replace(replacer, (_, sign, rest) => `${sign} ${rest}`) ) .join('\n') @@ -70,13 +70,13 @@ export async function executeTimeline( .reduce((total, current) => total + current, 0) // Changes happen in the next frame - await new Promise(resolve => d.nextFrame(resolve)) + await new Promise((resolve) => d.nextFrame(resolve)) // We wait for the amount of the duration - await new Promise(resolve => d.setTimeout(resolve, totalDuration)) + await new Promise((resolve) => d.setTimeout(resolve, totalDuration)) // We wait an additional next frame so that we know that we are done - await new Promise(resolve => d.nextFrame(resolve)) + await new Promise((resolve) => d.nextFrame(resolve)) }, Promise.resolve()) if (snapshots.length <= 0) { @@ -128,7 +128,7 @@ export async function executeTimeline( .replace(/Snapshot Diff:\n/g, '') ) .split('\n') - .map(line => ` ${line}`) + .map((line) => ` ${line}`) .join('\n')}` }) .filter(Boolean) diff --git a/packages/@headlessui-vue/src/test-utils/interactions.test.ts b/packages/@headlessui-vue/src/test-utils/interactions.test.ts index 3dab1e8a0f..990276d573 100644 --- a/packages/@headlessui-vue/src/test-utils/interactions.test.ts +++ b/packages/@headlessui-vue/src/test-utils/interactions.test.ts @@ -1,12 +1,12 @@ import { render } from './vue-testing-library' import { type, shift, Keys } from './interactions' -import { defineComponent, h } from 'vue' +import { ComponentOptionsWithoutProps, defineComponent, h } from 'vue' type Events = 'onKeydown' | 'onKeyup' | 'onKeypress' | 'onClick' | 'onBlur' | 'onFocus' let events: Events[] = ['onKeydown', 'onKeyup', 'onKeypress', 'onClick', 'onBlur', 'onFocus'] -function renderTemplate(input: string | Partial[0]>) { +function renderTemplate(input: string | ComponentOptionsWithoutProps) { let defaultComponents = {} if (typeof input === 'string') { @@ -164,7 +164,7 @@ describe('Keyboard', () => { let state = { readyToCapture: false } function createProps(id: string) { - return events.reduce( + return events.reduce void)>>( (props, name) => { props[name] = (event: any) => { if (!state.readyToCapture) return @@ -202,7 +202,7 @@ describe('Keyboard', () => { await type([key(input)]) - let expected = result.map(e => event(e)) + let expected = result.map((e) => event(e)) expect(fired.length).toEqual(result.length) diff --git a/packages/@headlessui-vue/src/test-utils/interactions.ts b/packages/@headlessui-vue/src/test-utils/interactions.ts index dd483d0966..600e605d1a 100644 --- a/packages/@headlessui-vue/src/test-utils/interactions.ts +++ b/packages/@headlessui-vue/src/test-utils/interactions.ts @@ -1,4 +1,7 @@ import { fireEvent } from '@testing-library/dom' +import { disposables } from '../utils/disposables' + +let d = disposables() function nextFrame(cb: Function): void { setImmediate(() => @@ -33,7 +36,19 @@ export function shift(event: Partial) { } export function word(input: string): Partial[] { - return input.split('').map(key => ({ key })) + let result = input.split('').map((key) => ({ key })) + + d.enqueue(() => { + let element = document.activeElement + + if (element instanceof HTMLInputElement) { + fireEvent.change(element, { + target: Object.assign({}, element, { value: input }), + }) + } + }) + + return result } let Default = Symbol() @@ -76,6 +91,9 @@ let order: Record< function keypress(element, event) { return fireEvent.keyPress(element, event) }, + function input(element, event) { + return fireEvent.input(element, event) + }, function keyup(element, event) { return fireEvent.keyUp(element, event) }, @@ -134,7 +152,7 @@ export async function type(events: Partial[], element = document. let actions = order[event.key!] ?? order[Default as any] for (let action of actions) { let checks = action.name.split('And') - if (checks.some(check => skip.has(check))) continue + if (checks.some((check) => skip.has(check))) continue let result = action(element, { type: action.name, @@ -159,9 +177,11 @@ export async function type(events: Partial[], element = document. // We don't want to actually wait in our tests, so let's advance jest.runAllTimers() + await d.workQueue() + await new Promise(nextFrame) } catch (err) { - Error.captureStackTrace(err, type) + if (err instanceof Error) Error.captureStackTrace(err, type) throw err } finally { jest.useRealTimers() @@ -178,7 +198,7 @@ export enum MouseButton { } export async function click( - element: Document | Element | Window | null, + element: Document | Element | Window | Node | null, button = MouseButton.Left ) { try { @@ -224,12 +244,12 @@ export async function click( await new Promise(nextFrame) } catch (err) { - Error.captureStackTrace(err, click) + if (err instanceof Error) Error.captureStackTrace(err, click) throw err } } -export async function focus(element: Document | Element | Window | null) { +export async function focus(element: Document | Element | Window | Node | null) { try { if (element === null) return expect(element).not.toBe(null) @@ -237,11 +257,10 @@ export async function focus(element: Document | Element | Window | null) { await new Promise(nextFrame) } catch (err) { - Error.captureStackTrace(err, focus) + if (err instanceof Error) Error.captureStackTrace(err, focus) throw err } } - export async function mouseEnter(element: Document | Element | Window | null) { try { if (element === null) return expect(element).not.toBe(null) @@ -252,7 +271,7 @@ export async function mouseEnter(element: Document | Element | Window | null) { await new Promise(nextFrame) } catch (err) { - Error.captureStackTrace(err, mouseEnter) + if (err instanceof Error) Error.captureStackTrace(err, mouseEnter) throw err } } @@ -266,7 +285,7 @@ export async function mouseMove(element: Document | Element | Window | null) { await new Promise(nextFrame) } catch (err) { - Error.captureStackTrace(err, mouseMove) + if (err instanceof Error) Error.captureStackTrace(err, mouseMove) throw err } } @@ -282,7 +301,7 @@ export async function mouseLeave(element: Document | Element | Window | null) { await new Promise(nextFrame) } catch (err) { - Error.captureStackTrace(err, mouseLeave) + if (err instanceof Error) Error.captureStackTrace(err, mouseLeave) throw err } } @@ -325,8 +344,8 @@ let focusableSelector = [ ? // TODO: Remove this once JSDOM fixes the issue where an element that is // "hidden" can be the document.activeElement, because this is not possible // in real browsers. - selector => `${selector}:not([tabindex='-1']):not([style*='display: none'])` - : selector => `${selector}:not([tabindex='-1'])` + (selector) => `${selector}:not([tabindex='-1']):not([style*='display: none'])` + : (selector) => `${selector}:not([tabindex='-1'])` ) .join(',') diff --git a/packages/@headlessui-vue/src/test-utils/suppress-console-logs.ts b/packages/@headlessui-vue/src/test-utils/suppress-console-logs.ts index 8e63bfeb05..b2833c996a 100644 --- a/packages/@headlessui-vue/src/test-utils/suppress-console-logs.ts +++ b/packages/@headlessui-vue/src/test-utils/suppress-console-logs.ts @@ -5,10 +5,10 @@ type FunctionPropertyNames = { export function suppressConsoleLogs( cb: (...args: T) => void, - type: FunctionPropertyNames = 'warn' + type: FunctionPropertyNames = 'warn' ) { return (...args: T) => { - let spy = jest.spyOn(global.console, type).mockImplementation(jest.fn()) + let spy = jest.spyOn(globalThis.console, type).mockImplementation(jest.fn()) return new Promise((resolve, reject) => { Promise.resolve(cb(...args)).then(resolve, reject) diff --git a/packages/@headlessui-vue/src/utils/calculate-active-index.ts b/packages/@headlessui-vue/src/utils/calculate-active-index.ts index cc296a9068..16ed66ffb0 100644 --- a/packages/@headlessui-vue/src/utils/calculate-active-index.ts +++ b/packages/@headlessui-vue/src/utils/calculate-active-index.ts @@ -40,7 +40,7 @@ export function calculateActiveIndex( let nextActiveIndex = (() => { switch (action.focus) { case Focus.First: - return items.findIndex(item => !resolvers.resolveDisabled(item)) + return items.findIndex((item) => !resolvers.resolveDisabled(item)) case Focus.Previous: { let idx = items @@ -64,13 +64,13 @@ export function calculateActiveIndex( let idx = items .slice() .reverse() - .findIndex(item => !resolvers.resolveDisabled(item)) + .findIndex((item) => !resolvers.resolveDisabled(item)) if (idx === -1) return idx return items.length - 1 - idx } case Focus.Specific: - return items.findIndex(item => resolvers.resolveId(item) === action.id) + return items.findIndex((item) => resolvers.resolveId(item) === action.id) case Focus.Nothing: return null diff --git a/packages/@headlessui-vue/src/utils/disposables.ts b/packages/@headlessui-vue/src/utils/disposables.ts index 7c9a388338..4c0f89c0f8 100644 --- a/packages/@headlessui-vue/src/utils/disposables.ts +++ b/packages/@headlessui-vue/src/utils/disposables.ts @@ -1,7 +1,12 @@ export function disposables() { let disposables: Function[] = [] + let queue: Function[] = [] let api = { + enqueue(fn: Function) { + queue.push(fn) + }, + requestAnimationFrame(...args: Parameters) { let raf = requestAnimationFrame(...args) api.add(() => cancelAnimationFrame(raf)) @@ -27,6 +32,12 @@ export function disposables() { dispose() } }, + + async workQueue() { + for (let handle of queue.splice(0)) { + await handle() + } + }, } return api diff --git a/packages/@headlessui-vue/src/utils/focus-management.ts b/packages/@headlessui-vue/src/utils/focus-management.ts index c2dca21ae3..06ac5bd6d3 100644 --- a/packages/@headlessui-vue/src/utils/focus-management.ts +++ b/packages/@headlessui-vue/src/utils/focus-management.ts @@ -18,8 +18,8 @@ let focusableSelector = [ ? // TODO: Remove this once JSDOM fixes the issue where an element that is // "hidden" can be the document.activeElement, because this is not possible // in real browsers. - selector => `${selector}:not([tabindex='-1']):not([style*='display: none'])` - : selector => `${selector}:not([tabindex='-1'])` + (selector) => `${selector}:not([tabindex='-1']):not([style*='display: none'])` + : (selector) => `${selector}:not([tabindex='-1'])` ) .join(',') diff --git a/packages/@headlessui-vue/src/utils/match.ts b/packages/@headlessui-vue/src/utils/match.ts index 80496d12a2..c4becd32cd 100644 --- a/packages/@headlessui-vue/src/utils/match.ts +++ b/packages/@headlessui-vue/src/utils/match.ts @@ -12,7 +12,7 @@ export function match `"${key}"`) + .map((key) => `"${key}"`) .join(', ')}.` ) if (Error.captureStackTrace) Error.captureStackTrace(error, match) diff --git a/packages/@headlessui-vue/src/utils/render.test.ts b/packages/@headlessui-vue/src/utils/render.test.ts index 0bc0e026a8..287ce0ff30 100644 --- a/packages/@headlessui-vue/src/utils/render.test.ts +++ b/packages/@headlessui-vue/src/utils/render.test.ts @@ -1,4 +1,4 @@ -import { defineComponent } from 'vue' +import { defineComponent, ComponentOptionsWithoutProps } from 'vue' import { render as testRender } from '../test-utils/vue-testing-library' import { render } from './render' @@ -13,7 +13,7 @@ let Dummy = defineComponent({ }, }) -function renderTemplate(input: string | Partial[0]>) { +function renderTemplate(input: string | ComponentOptionsWithoutProps) { let defaultComponents = { Dummy } if (typeof input === 'string') { @@ -34,9 +34,7 @@ describe('Validation', () => { expect.hasAssertions() renderTemplate({ - template: html` - Contents - `, + template: html` Contents `, errorCaptured(err) { expect(err as Error).toEqual( new Error( diff --git a/packages/@headlessui-vue/src/utils/render.ts b/packages/@headlessui-vue/src/utils/render.ts index 27c3b77428..7936a0b001 100644 --- a/packages/@headlessui-vue/src/utils/render.ts +++ b/packages/@headlessui-vue/src/utils/render.ts @@ -98,7 +98,7 @@ function _render({ `However we need to passthrough the following props:`, Object.keys(passThroughProps) .concat(Object.keys(attrs)) - .map(line => ` - ${line}`) + .map((line) => ` - ${line}`) .join('\n'), '', 'You can apply a few solutions:', @@ -106,7 +106,7 @@ function _render({ 'Add an `as="..."` prop, to ensure that we render an actual element instead of a "template".', 'Render a single element as the child so that we can forward the props onto that element.', ] - .map(line => ` - ${line}`) + .map((line) => ` - ${line}`) .join('\n'), ].join('\n') ) @@ -125,12 +125,15 @@ function _render({ return h(as, passThroughProps, children) } -export function omit>(object: T, keysToOmit: string[] = []) { +export function omit, Keys extends keyof T>( + object: T, + keysToOmit: readonly Keys[] = [] +) { let clone = Object.assign({}, object) for (let key of keysToOmit) { if (key in clone) delete clone[key] } - return clone + return clone as Omit } function isValidElement(input: any): boolean { diff --git a/packages/@headlessui-vue/tsconfig.json b/packages/@headlessui-vue/tsconfig.json index a62faa1a0b..cc575b4b35 100644 --- a/packages/@headlessui-vue/tsconfig.json +++ b/packages/@headlessui-vue/tsconfig.json @@ -24,7 +24,6 @@ "allowJs": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, - "noEmit": true, "resolveJsonModule": true, "isolatedModules": true }, diff --git a/packages/@headlessui-vue/tsconfig.tsdx.json b/packages/@headlessui-vue/tsconfig.tsdx.json deleted file mode 100644 index fc8520e737..0000000000 --- a/packages/@headlessui-vue/tsconfig.tsdx.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "./tsconfig.json" -} diff --git a/packages/@headlessui-vue/tsdx.config.js b/packages/@headlessui-vue/tsdx.config.js deleted file mode 100644 index 8a2668d598..0000000000 --- a/packages/@headlessui-vue/tsdx.config.js +++ /dev/null @@ -1,15 +0,0 @@ -const globals = { - vue: 'Vue', -} - -module.exports = { - rollup(config, opts) { - for (let key in globals) config.output.globals[key] = globals[key] - if (opts.format === 'esm') { - config = { ...config, preserveModules: true } - config.output = { ...config.output, dir: 'dist/', entryFileNames: '[name].esm.js' } - delete config.output.file - } - return config - }, -} diff --git a/packages/@headlessui-vue/types/jest.d.ts b/packages/@headlessui-vue/types/jest.d.ts new file mode 100644 index 0000000000..61902a8f06 --- /dev/null +++ b/packages/@headlessui-vue/types/jest.d.ts @@ -0,0 +1,9 @@ +export {} + +declare global { + namespace jest { + interface Matchers { + toBeWithinRenderFrame(actual: number): R + } + } +} diff --git a/packages/playground-react/next-env.d.ts b/packages/playground-react/next-env.d.ts new file mode 100644 index 0000000000..4f11a03dc6 --- /dev/null +++ b/packages/playground-react/next-env.d.ts @@ -0,0 +1,5 @@ +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/packages/playground-react/next.config.js b/packages/playground-react/next.config.js new file mode 100644 index 0000000000..5b8efdfbd8 --- /dev/null +++ b/packages/playground-react/next.config.js @@ -0,0 +1,5 @@ +module.exports = { + devIndicators: { + autoPrerender: false, + }, +} diff --git a/packages/playground-react/package.json b/packages/playground-react/package.json new file mode 100644 index 0000000000..ad6f0012d6 --- /dev/null +++ b/packages/playground-react/package.json @@ -0,0 +1,22 @@ +{ + "name": "playground-react", + "private": true, + "version": "0.0.0", + "scripts": { + "prebuild": "yarn workspace @headlessui/react build", + "dev:headlessui": "yarn workspace @headlessui/react watch", + "dev:next": "next dev", + "dev": "npm-run-all -p dev:*", + "build": "next build", + "start": "next start", + "clean": "rimraf ./.next" + }, + "dependencies": { + "@headlessui/react": "*", + "@popperjs/core": "^2.6.0", + "framer-motion": "^6.0.0", + "next": "^12.0.8", + "react": "16.14.0", + "react-dom": "16.14.0" + } +} diff --git a/packages/playground-react/pages/_app.tsx b/packages/playground-react/pages/_app.tsx new file mode 100644 index 0000000000..ed848be441 --- /dev/null +++ b/packages/playground-react/pages/_app.tsx @@ -0,0 +1,236 @@ +import React, { useState, useEffect } from 'react' +import Link from 'next/link' +import Head from 'next/head' + +function disposables() { + let disposables: Function[] = [] + + let api = { + requestAnimationFrame(...args: Parameters) { + let raf = requestAnimationFrame(...args) + api.add(() => cancelAnimationFrame(raf)) + }, + + nextFrame(...args: Parameters) { + api.requestAnimationFrame(() => { + api.requestAnimationFrame(...args) + }) + }, + + setTimeout(...args: Parameters) { + let timer = setTimeout(...args) + api.add(() => clearTimeout(timer)) + }, + + add(cb: () => void) { + disposables.push(cb) + }, + + dispose() { + for (let dispose of disposables.splice(0)) { + dispose() + } + }, + } + + return api +} + +export function useDisposables() { + // Using useState instead of useRef so that we can use the initializer function. + let [d] = useState(disposables) + useEffect(() => () => d.dispose(), [d]) + return d +} + +function NextLink(props: React.ComponentProps<'a'>) { + let { href, children, ...rest } = props + return ( + + {children} + + ) +} + +enum KeyDisplayMac { + ArrowUp = '↑', + ArrowDown = '↓', + ArrowLeft = '←', + ArrowRight = '→', + Home = '↖', + End = '↘', + Alt = '⌥', + CapsLock = '⇪', + Meta = '⌘', + Shift = '⇧', + Control = '⌃', + Backspace = '⌫', + Delete = '⌦', + Enter = '↵', + Escape = '⎋', + Tab = '↹', + PageUp = '⇞', + PageDown = '⇟', + ' ' = '␣', +} + +enum KeyDisplayWindows { + ArrowUp = '↑', + ArrowDown = '↓', + ArrowLeft = '←', + ArrowRight = '→', + Meta = 'Win', + Control = 'Ctrl', + Backspace = '⌫', + Delete = 'Del', + Escape = 'Esc', + PageUp = 'PgUp', + PageDown = 'PgDn', + ' ' = '␣', +} + +function tap(value: T, cb: (value: T) => void) { + cb(value) + return value +} + +function useKeyDisplay() { + let [mounted, setMounted] = useState(false) + + useEffect(() => { + setMounted(true) + }, []) + + if (!mounted) return {} + let isMac = navigator.userAgent.indexOf('Mac OS X') !== -1 + return isMac ? KeyDisplayMac : KeyDisplayWindows +} + +function KeyCaster() { + let [keys, setKeys] = useState([]) + let d = useDisposables() + let KeyDisplay = useKeyDisplay() + + useEffect(() => { + function handler(event: KeyboardEvent) { + setKeys((current) => [ + event.shiftKey && event.key !== 'Shift' + ? KeyDisplay[`Shift${event.key}`] ?? event.key + : KeyDisplay[event.key] ?? event.key, + ...current, + ]) + d.setTimeout(() => setKeys((current) => tap(current.slice(), (clone) => clone.pop())), 2000) + } + + window.addEventListener('keydown', handler, true) + return () => window.removeEventListener('keydown', handler, true) + }, [d, KeyDisplay]) + + if (keys.length <= 0) return null + + return ( +
+ {keys.slice().reverse().join(' ')} +
+ ) +} + +function MyApp({ Component, pageProps }) { + return ( + <> + + + + + + + + + + + +
+
+ + + +
+ + + +
+ +
+
+ + ) +} + +function Logo({ className }) { + return ( + + + + + + + + + + + + + + + + + + ) +} + +export default MyApp diff --git a/packages/playground-react/pages/_error.tsx b/packages/playground-react/pages/_error.tsx new file mode 100644 index 0000000000..d20a86ce54 --- /dev/null +++ b/packages/playground-react/pages/_error.tsx @@ -0,0 +1,63 @@ +import React from 'react' +import ErrorPage from 'next/error' +import Head from 'next/head' +import Link from 'next/link' + +import { ExamplesType, resolveAllExamples } from '../utils/resolve-all-examples' + +function NextLink(props: React.ComponentProps<'a'>) { + let { href, children, ...rest } = props + return ( + + {children} + + ) +} + +export async function getStaticProps() { + return { + props: { + examples: await resolveAllExamples('pages'), + }, + } +} + +export default function Page(props: { examples: false | ExamplesType[] }) { + if (props.examples === false) { + return + } + + return ( + <> + + Examples + + +
+
+

Examples

+ +
+
+ + ) +} + +export function Examples(props: { examples: ExamplesType[] }) { + return ( +
    + {props.examples.map((example) => ( +
  • + {example.children ? ( +

    {example.name}

    + ) : ( + + {example.name} + + )} + {example.children && } +
  • + ))} +
+ ) +} diff --git a/packages/playground-react/pages/combobox/combobox-with-pure-tailwind.tsx b/packages/playground-react/pages/combobox/combobox-with-pure-tailwind.tsx new file mode 100644 index 0000000000..3a5ea2d265 --- /dev/null +++ b/packages/playground-react/pages/combobox/combobox-with-pure-tailwind.tsx @@ -0,0 +1,136 @@ +import React, { useState, useEffect } from 'react' +import { Combobox } from '@headlessui/react' + +import { classNames } from '../../utils/class-names' + +let everybody = [ + 'Wade Cooper', + 'Arlene Mccoy', + 'Devon Webb', + 'Tom Cook', + 'Tanya Fox', + 'Hellen Schmidt', + 'Caroline Schultz', + 'Mason Heaney', + 'Claudie Smitham', + 'Emil Schaefer', +] + +function useDebounce(value: T, delay: number) { + let [debouncedValue, setDebouncedValue] = useState(value) + useEffect(() => { + let timer = setTimeout(() => setDebouncedValue(value), delay) + return () => clearTimeout(timer) + }, [value, delay]) + return debouncedValue +} +export default function Home() { + let [query, setQuery] = useState('') + let [activePerson, setActivePerson] = useState(everybody[2]) + + // Mimic delayed response from an API + let actualQuery = useDebounce(query, 0 /* Change to higher value like 100 for testing purposes */) + + // Choose a random person on mount + useEffect(() => { + setActivePerson(everybody[Math.floor(Math.random() * everybody.length)]) + }, []) + + let people = + actualQuery === '' + ? everybody + : everybody.filter((person) => person.toLowerCase().includes(actualQuery.toLowerCase())) + + return ( +
+
+
Selected person: {activePerson}
+
+ { + setActivePerson(value) + }} + as="div" + > + + Assigned to + + +
+ + setQuery(e.target.value)} + className="border-none px-3 py-1 outline-none" + /> + + + + + + + + + +
+ + {people.map((name) => ( + { + return classNames( + 'relative cursor-default select-none py-2 pl-3 pr-9 focus:outline-none', + active ? 'bg-indigo-600 text-white' : 'text-gray-900' + ) + }} + > + {({ active, selected }) => ( + <> + + {name} + + {selected && ( + + + + + + )} + + )} + + ))} + +
+
+
+
+
+
+ ) +} diff --git a/packages/playground-react/pages/combobox/command-palette-with-groups.tsx b/packages/playground-react/pages/combobox/command-palette-with-groups.tsx new file mode 100644 index 0000000000..e0418d0e95 --- /dev/null +++ b/packages/playground-react/pages/combobox/command-palette-with-groups.tsx @@ -0,0 +1,150 @@ +import React, { useState, useEffect, Fragment } from 'react' +import { Combobox } from '@headlessui/react' + +import { classNames } from '../../utils/class-names' + +let everybody = [ + { id: 1, img: 'https://github.com/adamwathan.png', name: 'Adam Wathan' }, + { id: 2, img: 'https://github.com/sschoger.png', name: 'Steve Schoger' }, + { id: 3, img: 'https://github.com/bradlc.png', name: 'Brad Cornes' }, + { id: 4, img: 'https://github.com/simonswiss.png', name: 'Simon Vrachliotis' }, + { id: 5, img: 'https://github.com/robinmalfait.png', name: 'Robin Malfait' }, + { + id: 6, + img: 'https://pbs.twimg.com/profile_images/1478879681491394569/eV2PyCnm_400x400.jpg', + name: 'James McDonald', + }, + { id: 7, img: 'https://github.com/reinink.png', name: 'Jonathan Reinink' }, + { id: 8, img: 'https://github.com/thecrypticace.png', name: 'Jordan Pittman' }, +] + +export default function Home() { + let [query, setQuery] = useState('') + let [activePerson, setActivePerson] = useState(everybody[2]) + + function setPerson(person) { + setActivePerson(person) + setQuery(person.name ?? '') + } + + // Choose a random person on mount + useEffect(() => { + setPerson(everybody[Math.floor(Math.random() * everybody.length)]) + }, []) + + let people = + query === '' + ? everybody + : everybody.filter((person) => person.name.toLowerCase().includes(query.toLowerCase())) + + let groups = people.reduce((groups, person) => { + let lastNameLetter = person.name.split(' ')[1][0] + + groups.set(lastNameLetter, [...(groups.get(lastNameLetter) || []), person]) + + return groups + }, new Map()) + + return ( +
+
+
+ setPerson(person)} + className="w-full overflow-hidden rounded border border-black/5 bg-white bg-clip-padding shadow-sm" + > + {({ activeOption }) => { + return ( +
+ setQuery(e.target.value)} + className="w-full rounded-none border-none bg-none px-3 py-1 outline-none" + placeholder="Search users…" + displayValue={(item: typeof activeOption) => item?.name} + /> +
+ + {Array.from(groups.entries()) + .sort(([letterA], [letterZ]) => letterA.localeCompare(letterZ)) + .map(([letter, people]) => ( + +
{letter}
+ {people.map((person) => ( + { + return classNames( + 'relative flex cursor-default select-none space-x-4 py-2 pl-3 pr-9 focus:outline-none', + active ? 'bg-indigo-600 text-white' : 'text-gray-900' + ) + }} + > + {({ active, selected }) => ( + <> + + + {person.name} + + {active && ( + + + + + + )} + + )} + + ))} +
+ ))} +
+ + {people.length === 0 ? ( +
No person selected
+ ) : activeOption === null ? null : ( +
+
+
+ +
{activeOption.name}
+
Obviously cool person
+
+
+
+ )} +
+
+ ) + }} +
+
+
+
+ ) +} diff --git a/packages/playground-react/pages/combobox/command-palette.tsx b/packages/playground-react/pages/combobox/command-palette.tsx new file mode 100644 index 0000000000..25dc1da838 --- /dev/null +++ b/packages/playground-react/pages/combobox/command-palette.tsx @@ -0,0 +1,135 @@ +import React, { useState, useEffect } from 'react' +import { Combobox } from '@headlessui/react' + +import { classNames } from '../../utils/class-names' + +let everybody = [ + { id: 1, img: 'https://github.com/adamwathan.png', name: 'Adam Wathan' }, + { id: 2, img: 'https://github.com/sschoger.png', name: 'Steve Schoger' }, + { id: 3, img: 'https://github.com/bradlc.png', name: 'Brad Cornes' }, + { id: 4, img: 'https://github.com/simonswiss.png', name: 'Simon Vrachliotis' }, + { id: 5, img: 'https://github.com/robinmalfait.png', name: 'Robin Malfait' }, + { + id: 6, + img: 'https://pbs.twimg.com/profile_images/1478879681491394569/eV2PyCnm_400x400.jpg', + name: 'James McDonald', + }, + { id: 7, img: 'https://github.com/reinink.png', name: 'Jonathan Reinink' }, + { id: 8, img: 'https://github.com/thecrypticace.png', name: 'Jordan Pittman' }, +] + +export default function Home() { + let [query, setQuery] = useState('') + let [activePerson, setActivePerson] = useState(everybody[2]) + + // Choose a random person on mount + useEffect(() => { + setActivePerson(everybody[Math.floor(Math.random() * everybody.length)]) + }, []) + + let people = + query === '' + ? everybody + : everybody.filter((person) => person.name.toLowerCase().includes(query.toLowerCase())) + + return ( +
+
+
+ setActivePerson(person)} + className="w-full overflow-hidden rounded border border-black/5 bg-white bg-clip-padding shadow-sm" + > + {({ activeOption, open }) => { + return ( +
+ setQuery(e.target.value)} + className="w-full rounded-none border-none px-3 py-1 outline-none" + placeholder="Search users…" + displayValue={(item: typeof activePerson) => item?.name} + /> +
+ + {people.map((person) => ( + { + return classNames( + 'relative flex cursor-default select-none space-x-4 py-2 pl-3 pr-9 focus:outline-none', + active ? 'bg-indigo-600 text-white' : 'text-gray-900' + ) + }} + > + {({ active, selected }) => ( + <> + + + {person.name} + + {active && ( + + + + + + )} + + )} + + ))} + + + {people.length === 0 ? ( +
No person selected
+ ) : activeOption === null ? null : ( +
+
+
+ +
{activeOption.name}
+
Obviously cool person
+
+
+
+ )} +
+
+ ) + }} +
+
+
+
+ ) +} diff --git a/packages/playground-react/pages/dialog/dialog.tsx b/packages/playground-react/pages/dialog/dialog.tsx new file mode 100644 index 0000000000..3b7fd6b6f4 --- /dev/null +++ b/packages/playground-react/pages/dialog/dialog.tsx @@ -0,0 +1,238 @@ +import React, { useState, Fragment } from 'react' +import { Dialog, Menu, Portal, Transition } from '@headlessui/react' +import { usePopper } from '../../utils/hooks/use-popper' +import { classNames } from '../../utils/class-names' + +function resolveClass({ active, disabled }) { + return classNames( + 'flex justify-between w-full px-4 py-2 text-sm leading-5 text-left', + active ? 'bg-gray-100 text-gray-900' : 'text-gray-700', + disabled && 'cursor-not-allowed opacity-50' + ) +} + +function Nested({ onClose, level = 0 }) { + let [showChild, setShowChild] = useState(false) + + return ( + <> + + +
+

Level: {level}

+
+ + + +
+
+ {showChild && setShowChild(false)} level={level + 1} />} +
+ + ) +} + +export default function Home() { + let [isOpen, setIsOpen] = useState(false) + let [nested, setNested] = useState(false) + + let [trigger, container] = usePopper({ + placement: 'bottom-end', + strategy: 'fixed', + modifiers: [{ name: 'offset', options: { offset: [0, 10] } }], + }) + + return ( + <> + + + + {nested && setNested(false)} />} + + console.log('done')}> + +
+
+ + + + + + {/* This element is to trick the browser into centering the modal contents. */} + +
+
+
+
+ {/* Heroicon name: exclamation */} + +
+
+ + Deactivate account + +
+

+ Are you sure you want to deactivate your account? All of your data will + be permanently removed. This action cannot be undone. +

+
+ + + + Choose a reason + + + + + + + + + +
+

Signed in as

+

+ tom@example.com +

+
+ +
+ + Account settings + + + Support + + + New feature (soon) + + + License + +
+ +
+ + Sign out + +
+
+
+
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+ + ) +} diff --git a/packages/playground-react/pages/disclosure/disclosure.tsx b/packages/playground-react/pages/disclosure/disclosure.tsx new file mode 100644 index 0000000000..e0b6d67322 --- /dev/null +++ b/packages/playground-react/pages/disclosure/disclosure.tsx @@ -0,0 +1,25 @@ +import React from 'react' +import { Disclosure, Transition } from '@headlessui/react' + +export default function Home() { + return ( +
+
+ + Trigger + + + Content + + +
+
+ ) +} diff --git a/packages/playground-react/pages/listbox/listbox-with-pure-tailwind.tsx b/packages/playground-react/pages/listbox/listbox-with-pure-tailwind.tsx new file mode 100644 index 0000000000..b6efaf2e55 --- /dev/null +++ b/packages/playground-react/pages/listbox/listbox-with-pure-tailwind.tsx @@ -0,0 +1,115 @@ +import React, { useState, useEffect } from 'react' +import { Listbox } from '@headlessui/react' + +import { classNames } from '../../utils/class-names' + +let people = [ + 'Wade Cooper', + 'Arlene Mccoy', + 'Devon Webb', + 'Tom Cook', + 'Tanya Fox', + 'Hellen Schmidt', + 'Caroline Schultz', + 'Mason Heaney', + 'Claudie Smitham', + 'Emil Schaefer', +] + +export default function Home() { + let [active, setActivePerson] = useState(people[2]) + + // Choose a random person on mount + useEffect(() => { + setActivePerson(people[Math.floor(Math.random() * people.length)]) + }, []) + + return ( +
+
+
+ { + console.log('value:', value) + setActivePerson(value) + }} + > + + Assigned to + + +
+ + + {active} + + + + + + + + +
+ + {people.map((name) => ( + { + return classNames( + 'relative cursor-default select-none py-2 pl-3 pr-9 focus:outline-none', + active ? 'bg-indigo-600 text-white' : 'text-gray-900' + ) + }} + > + {({ active, selected }) => ( + <> + + {name} + + {selected && ( + + + + + + )} + + )} + + ))} + +
+
+
+
+
+
+ ) +} diff --git a/packages/playground-react/pages/listbox/multiple-elements.tsx b/packages/playground-react/pages/listbox/multiple-elements.tsx new file mode 100644 index 0000000000..dc97459358 --- /dev/null +++ b/packages/playground-react/pages/listbox/multiple-elements.tsx @@ -0,0 +1,134 @@ +import React, { useState, useEffect } from 'react' +import { Listbox } from '@headlessui/react' +import { classNames } from '../../utils/class-names' + +let people = [ + 'Wade Cooper', + 'Arlene Mccoy', + 'Devon Webb', + 'Tom Cook', + 'Tanya Fox', + 'Hellen Schmidt', + 'Caroline Schultz', + 'Mason Heaney', + 'Claudie Smitham', + 'Emil Schaefer', +] + +export default function Home() { + return ( +
+ + +
+ +
+ +
+
+ + +
+ ) +} + +function PeopleList() { + let [active, setActivePerson] = useState(people[2]) + + // Choose a random person on mount + useEffect(() => { + setActivePerson(people[Math.floor(Math.random() * people.length)]) + }, []) + + return ( +
+
+ { + console.log('value:', value) + setActivePerson(value) + }} + > + + Assigned to + + +
+ + + {active} + + + + + + + + +
+ + {people.map((name) => ( + { + return classNames( + 'relative cursor-default select-none py-2 pl-3 pr-9 focus:outline-none', + active ? 'bg-indigo-600 text-white' : 'text-gray-900' + ) + }} + > + {({ active, selected }) => ( + <> + + {name} + + {selected && ( + + + + + + )} + + )} + + ))} + +
+
+
+
+
+ ) +} diff --git a/packages/playground-react/pages/menu/menu-with-framer-motion.tsx b/packages/playground-react/pages/menu/menu-with-framer-motion.tsx new file mode 100644 index 0000000000..9fa10e3df0 --- /dev/null +++ b/packages/playground-react/pages/menu/menu-with-framer-motion.tsx @@ -0,0 +1,111 @@ +import React from 'react' +import Link from 'next/link' +import { Menu } from '@headlessui/react' +import { AnimatePresence, motion } from 'framer-motion' + +import { classNames } from '../../utils/class-names' + +export default function Home() { + return ( +
+
+ + {({ open }) => ( + <> + + + Options + + + + + + + + {open && ( + +
+

Signed in as

+

+ tom@example.com +

+
+ +
+ Account settings + + Support + + + New feature (soon) + + License +
+ +
+ +
+
+ )} +
+ + )} +
+
+
+ ) +} + +function NextLink(props: React.ComponentProps<'a'>) { + let { href, children, ...rest } = props + return ( + + {children} + + ) +} + +function SignOutButton(props) { + return ( +
{ + e.preventDefault() + alert('SIGNED OUT') + }} + className="w-full" + > + +
+ ) +} + +function Item(props: React.ComponentProps) { + return ( + + classNames( + 'block w-full px-4 py-2 text-left text-sm leading-5 text-gray-700', + active && 'bg-gray-100 text-gray-900', + disabled && 'cursor-not-allowed opacity-50' + ) + } + {...props} + /> + ) +} diff --git a/packages/playground-react/pages/menu/menu-with-popper.tsx b/packages/playground-react/pages/menu/menu-with-popper.tsx new file mode 100644 index 0000000000..e8ee320c91 --- /dev/null +++ b/packages/playground-react/pages/menu/menu-with-popper.tsx @@ -0,0 +1,95 @@ +import React, { ReactNode, useState, useEffect } from 'react' +import { createPortal } from 'react-dom' +import { Menu } from '@headlessui/react' + +import { usePopper } from '../../utils/hooks/use-popper' +import { classNames } from '../../utils/class-names' + +export default function Home() { + let [trigger, container] = usePopper({ + placement: 'bottom-end', + strategy: 'fixed', + modifiers: [{ name: 'offset', options: { offset: [0, 10] } }], + }) + + function resolveClass({ active, disabled }) { + return classNames( + 'block w-full text-left px-4 py-2 text-sm leading-5 text-gray-700', + active && 'bg-gray-100 text-gray-900', + disabled && 'cursor-not-allowed opacity-50' + ) + } + + return ( +
+
+ + + + Options + + + + + + + + +
+

Signed in as

+

+ tom@example.com +

+
+ +
+ + Account settings + + + {(data) => ( + + Support + + )} + + + New feature (soon) + + + License + +
+ +
+ + Sign out + +
+
+
+
+
+
+ ) +} + +function Portal(props: { children: ReactNode }) { + let { children } = props + let [mounted, setMounted] = useState(false) + + useEffect(() => setMounted(true), []) + + if (!mounted) return null + return createPortal(children, document.body) +} diff --git a/packages/playground-react/pages/menu/menu-with-transition-and-popper.tsx b/packages/playground-react/pages/menu/menu-with-transition-and-popper.tsx new file mode 100644 index 0000000000..c1296c564e --- /dev/null +++ b/packages/playground-react/pages/menu/menu-with-transition-and-popper.tsx @@ -0,0 +1,89 @@ +import React from 'react' +import { Menu, Transition } from '@headlessui/react' + +import { usePopper } from '../../utils/hooks/use-popper' +import { classNames } from '../../utils/class-names' + +export default function Home() { + let [trigger, container] = usePopper({ + placement: 'bottom-end', + strategy: 'fixed', + modifiers: [{ name: 'offset', options: { offset: [0, 10] } }], + }) + + function resolveClass({ active, disabled }) { + return classNames( + 'flex justify-between w-full px-4 py-2 text-sm leading-5 text-left', + active ? 'bg-gray-100 text-gray-900' : 'text-gray-700', + disabled && 'cursor-not-allowed opacity-50' + ) + } + + return ( +
+
+ + + + Options + + + + + + +
+ + +
+

Signed in as

+

+ tom@example.com +

+
+ +
+ + Account settings + + + {(data) => ( + + Support + + )} + + + New feature (soon) + + + License + +
+
+ + Sign out + +
+
+
+
+
+
+
+ ) +} diff --git a/packages/playground-react/pages/menu/menu-with-transition.tsx b/packages/playground-react/pages/menu/menu-with-transition.tsx new file mode 100644 index 0000000000..9b277e5cc3 --- /dev/null +++ b/packages/playground-react/pages/menu/menu-with-transition.tsx @@ -0,0 +1,73 @@ +import React from 'react' +import { Menu, Transition } from '@headlessui/react' +import { classNames } from '../../utils/class-names' + +export default function Home() { + function resolveClass({ active, disabled }) { + return classNames( + 'flex justify-between w-full px-4 py-2 text-sm leading-5 text-left', + active ? 'bg-gray-100 text-gray-900' : 'text-gray-700', + disabled && 'cursor-not-allowed opacity-50' + ) + } + + return ( +
+
+ + + + Options + + + + + + + + +
+

Signed in as

+

+ tom@example.com +

+
+ +
+ + Account settings + + + Support + + + New feature (soon) + + + License + +
+ +
+ + Sign out + +
+
+
+
+
+
+ ) +} diff --git a/packages/playground-react/pages/menu/menu.tsx b/packages/playground-react/pages/menu/menu.tsx new file mode 100644 index 0000000000..0b8b9bda96 --- /dev/null +++ b/packages/playground-react/pages/menu/menu.tsx @@ -0,0 +1,72 @@ +import React from 'react' +import { Menu } from '@headlessui/react' + +import { classNames } from '../../utils/class-names' + +export default function Home() { + return ( +
+
+ + + + Options + + + + + + + +
+

Signed in as

+

+ tom@example.com +

+
+ +
+ Account settings + Support + + New feature (soon) + + License +
+
+ Sign out +
+
+
+
+
+ ) +} + +function CustomMenuItem(props: React.ComponentProps) { + return ( + + {({ active, disabled }) => ( + + {props.children} + ⌘K + + )} + + ) +} diff --git a/packages/playground-react/pages/menu/multiple-elements.tsx b/packages/playground-react/pages/menu/multiple-elements.tsx new file mode 100644 index 0000000000..d0ec1284af --- /dev/null +++ b/packages/playground-react/pages/menu/multiple-elements.tsx @@ -0,0 +1,83 @@ +import React from 'react' +import { Menu } from '@headlessui/react' +import { classNames } from '../../utils/class-names' + +export default function Home() { + return ( +
+ + +
+
+ +
+
+ + +
+ ) +} + +function Dropdown() { + function resolveClass({ active, disabled }) { + return classNames( + 'block w-full text-left px-4 py-2 text-sm leading-5 text-gray-700', + active && 'bg-gray-100 text-gray-900', + disabled && 'cursor-not-allowed opacity-50' + ) + } + + return ( +
+ + + + Options + + + + + + + +
+

Signed in as

+

tom@example.com

+
+ +
+ + Account settings + + + {(data) => ( + + Support + + )} + + + New feature (soon) + + + License + +
+ +
+ + Sign out + +
+
+
+
+ ) +} diff --git a/packages/playground-react/pages/popover/popover.tsx b/packages/playground-react/pages/popover/popover.tsx new file mode 100644 index 0000000000..fa2d143dd3 --- /dev/null +++ b/packages/playground-react/pages/popover/popover.tsx @@ -0,0 +1,116 @@ +import React, { forwardRef, Fragment } from 'react' +import { Popover, Portal, Transition } from '@headlessui/react' +import { usePopper } from '../../utils/hooks/use-popper' + +let Button = forwardRef( + (props: React.ComponentProps<'button'>, ref: React.MutableRefObject) => { + return ( + + ) + } +) + +function Link(props: React.ComponentProps<'a'>) { + return ( + + {props.children} + + ) +} + +export default function Home() { + let options = { + placement: 'bottom-start' as const, + strategy: 'fixed' as const, + modifiers: [], + } + + let [reference1, popper1] = usePopper(options) + let [reference2, popper2] = usePopper(options) + + let links = ['First', 'Second', 'Third', 'Fourth'] + + return ( +
+ + + + + + + + + + Normal + + + {links.map((link, i) => ( + + Normal - {link} + + ))} + + + + + + + {links.map((link, i) => ( + Focus - {link} + ))} + + + + + + + + {links.map((link) => ( + Portal - {link} + ))} + + + + + + + + + {links.map((link) => ( + Focus in Portal - {link} + ))} + + + + + + +
+ ) +} diff --git a/packages/playground-react/pages/radio-group/radio-group.tsx b/packages/playground-react/pages/radio-group/radio-group.tsx new file mode 100644 index 0000000000..be855f2bf0 --- /dev/null +++ b/packages/playground-react/pages/radio-group/radio-group.tsx @@ -0,0 +1,101 @@ +import React, { useState } from 'react' +import { RadioGroup } from '@headlessui/react' +import { classNames } from '../../utils/class-names' + +export default function Home() { + let access = [ + { + id: 'access-1', + name: 'Public access', + description: 'This project would be available to anyone who has the link', + }, + { + id: 'access-2', + name: 'Private to Project Members', + description: 'Only members of this project would be able to access', + }, + { + id: 'access-3', + name: 'Private to you', + description: 'You are the only one able to access this project', + }, + ] + let [active, setActive] = useState() + + return ( +
+ Link before + +
+ +

Privacy setting

+
+ +
+ {access.map(({ id, name, description }, i) => { + return ( + + classNames( + // Rounded corners + i === 0 && 'rounded-tl-md rounded-tr-md', + access.length - 1 === i && 'rounded-bl-md rounded-br-md', + + // Shared + 'relative flex border p-4 focus:outline-none', + active ? 'z-10 border-indigo-200 bg-indigo-50' : 'border-gray-200' + ) + } + > + {({ active, checked }) => ( +
+
+ + {name} + + + {description} + +
+
+ {checked && ( + + + + )} +
+
+ )} +
+ ) + })} +
+
+
+ Link after +
+ ) +} diff --git a/packages/playground-react/pages/switch/switch-with-pure-tailwind.tsx b/packages/playground-react/pages/switch/switch-with-pure-tailwind.tsx new file mode 100644 index 0000000000..c392886717 --- /dev/null +++ b/packages/playground-react/pages/switch/switch-with-pure-tailwind.tsx @@ -0,0 +1,39 @@ +import React, { useState } from 'react' +import { Switch } from '@headlessui/react' + +import { classNames } from '../../utils/class-names' + +export default function Home() { + let [state, setState] = useState(false) + + return ( +
+ + Enable notifications + + + classNames( + 'focus:shadow-outline relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none', + checked ? 'bg-indigo-600' : 'bg-gray-200' + ) + } + > + {({ checked }) => ( + <> + + + )} + + +
+ ) +} diff --git a/packages/playground-react/pages/tabs/tabs-with-pure-tailwind.tsx b/packages/playground-react/pages/tabs/tabs-with-pure-tailwind.tsx new file mode 100644 index 0000000000..c1cc475644 --- /dev/null +++ b/packages/playground-react/pages/tabs/tabs-with-pure-tailwind.tsx @@ -0,0 +1,86 @@ +import React, { useState } from 'react' +import { Tab, Switch } from '@headlessui/react' + +import { classNames } from '../../utils/class-names' + +export default function Home() { + let tabs = [ + { name: 'My Account', content: 'Tab content for my account' }, + { name: 'Company', content: 'Tab content for company', disabled: true }, + { name: 'Team Members', content: 'Tab content for team members' }, + { name: 'Billing', content: 'Tab content for billing' }, + ] + + let [manual, setManual] = useState(false) + + return ( +
+ + Manual keyboard activation + + + classNames( + 'focus:shadow-outline relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none', + checked ? 'bg-indigo-600' : 'bg-gray-200' + ) + } + > + {({ checked }) => ( + + )} + + + + + + {tabs.map((tab, tabIdx) => ( + + classNames( + selected ? 'text-gray-900' : 'text-gray-500 hover:text-gray-700', + tabIdx === 0 ? 'rounded-l-lg' : '', + tabIdx === tabs.length - 1 ? 'rounded-r-lg' : '', + tab.disabled && 'opacity-50', + 'group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-center text-sm font-medium hover:bg-gray-50 focus:z-10' + ) + } + > + {({ selected }) => ( + <> + {tab.name} + {tab.disabled && (disabled)} + + ))} + + + + {tabs.map((tab) => ( + + {tab.content} + + ))} + + +
+ ) +} diff --git a/packages/playground-react/pages/transitions/component-examples/dropdown.tsx b/packages/playground-react/pages/transitions/component-examples/dropdown.tsx new file mode 100644 index 0000000000..d0df015c3a --- /dev/null +++ b/packages/playground-react/pages/transitions/component-examples/dropdown.tsx @@ -0,0 +1,98 @@ +import React, { useState } from 'react' +import Head from 'next/head' +import { Transition } from '@headlessui/react' + +export default function Home() { + return ( + <> + + Transition Component - Playground + + +
+ +
+ + ) +} + +function Dropdown() { + let [isOpen, setIsOpen] = useState(false) + + return ( +
+
+ + + +
+ + + + +
+ ) +} diff --git a/packages/playground-react/pages/transitions/component-examples/modal.tsx b/packages/playground-react/pages/transitions/component-examples/modal.tsx new file mode 100644 index 0000000000..caa21f7ec1 --- /dev/null +++ b/packages/playground-react/pages/transitions/component-examples/modal.tsx @@ -0,0 +1,168 @@ +import React, { useRef, useState } from 'react' +import { Transition } from '@headlessui/react' + +export default function Home() { + let [isOpen, setIsOpen] = useState(false) + function toggle() { + setIsOpen((v) => !v) + } + + let [email, setEmail] = useState('') + let [events, setEvents] = useState([]) + let inputRef = useRef(null) + + function addEvent(name) { + setEvents((existing) => [...existing, `${new Date().toJSON()} - ${name}`]) + } + + return ( +
+
+
+ + + +
+ +
    +

    Events:

    + {events.map((event, i) => ( +
  • + {event} +
  • + ))} +
+
+ + { + addEvent('Before enter') + }} + afterEnter={() => { + inputRef.current.focus() + addEvent('After enter') + }} + beforeLeave={() => { + addEvent('Before leave (before confirm)') + window.confirm('Are you sure?') + addEvent('Before leave (after confirm)') + }} + afterLeave={() => { + addEvent('After leave (before alert)') + window.alert('Consider it done!') + addEvent('After leave (after alert)') + setEmail('') + }} + > +
+ +
+
+
+
+ {/* This element is to trick the browser into centering the modal contents. */} + ​ + +
+
+
+ {/* Heroicon name: exclamation */} + + + +
+
+ +
+

+ Are you sure you want to deactivate your account? All of your data will be + permanently removed. This action cannot be undone. +

+
+
+
+ +
+ setEmail(event.target.value)} + id="email" + className="form-input block w-full px-3 sm:text-sm sm:leading-5" + placeholder="name@example.com" + /> +
+
+
+
+
+
+
+ + + + + + +
+
+
+
+
+ ) +} diff --git a/packages/playground-react/pages/transitions/component-examples/nested/hidden.tsx b/packages/playground-react/pages/transitions/component-examples/nested/hidden.tsx new file mode 100644 index 0000000000..3ea0d29b23 --- /dev/null +++ b/packages/playground-react/pages/transitions/component-examples/nested/hidden.tsx @@ -0,0 +1,60 @@ +import React, { useState, ReactNode } from 'react' +import { Transition } from '@headlessui/react' + +export default function Home() { + let [isOpen, setIsOpen] = useState(true) + + return ( + <> +
+
+ + + + + + + + + + + + + + + + + + + + +
+
+ + ) +} + +function Box({ children }: { children?: ReactNode }) { + return ( + +
+ This is a box + {children} +
+
+ ) +} diff --git a/packages/playground-react/pages/transitions/component-examples/nested/unmount.tsx b/packages/playground-react/pages/transitions/component-examples/nested/unmount.tsx new file mode 100644 index 0000000000..a5ccf08262 --- /dev/null +++ b/packages/playground-react/pages/transitions/component-examples/nested/unmount.tsx @@ -0,0 +1,60 @@ +import React, { useState, ReactNode } from 'react' +import { Transition } from '@headlessui/react' + +export default function Home() { + let [isOpen, setIsOpen] = useState(true) + + return ( + <> +
+
+ + + + + + + + + + + + + + + + + + + + +
+
+ + ) +} + +function Box({ children }: { children?: ReactNode }) { + return ( + +
+ This is a box + {children} +
+
+ ) +} diff --git a/packages/playground-react/pages/transitions/component-examples/peek-a-boo.tsx b/packages/playground-react/pages/transitions/component-examples/peek-a-boo.tsx new file mode 100644 index 0000000000..5cfba5bd8a --- /dev/null +++ b/packages/playground-react/pages/transitions/component-examples/peek-a-boo.tsx @@ -0,0 +1,38 @@ +import React, { useState } from 'react' +import { Transition } from '@headlessui/react' + +export default function Home() { + let [isOpen, setIsOpen] = useState(true) + + return ( + <> +
+
+ + + + + + Contents to show and hide + +
+
+ + ) +} diff --git a/packages/playground-react/pages/transitions/full-page-examples/full-page-transition.tsx b/packages/playground-react/pages/transitions/full-page-examples/full-page-transition.tsx new file mode 100644 index 0000000000..4eff1f5fae --- /dev/null +++ b/packages/playground-react/pages/transitions/full-page-examples/full-page-transition.tsx @@ -0,0 +1,181 @@ +import React, { useEffect, useRef, useState } from 'react' +import Head from 'next/head' +import { Transition } from '@headlessui/react' + +import { classNames } from '../../../utils/class-names' +import { match } from '../../../utils/match' + +export default function Shell() { + return ( + <> + + Transition Component - Full Page Transition + +
+
+ +
+
+ + ) +} + +function usePrevious(value: T) { + let ref = useRef(value) + useEffect(() => { + ref.current = value + }, [value]) + return ref.current +} + +enum Direction { + Forwards = ' -> ', + Backwards = ' <- ', +} + +let pages = ['Dashboard', 'Team', 'Projects', 'Calendar', 'Reports'] +let colors = [ + 'bg-gradient-to-r from-teal-400 to-blue-400', + 'bg-gradient-to-r from-blue-400 to-orange-400', + 'bg-gradient-to-r from-orange-400 to-purple-400', + 'bg-gradient-to-r from-purple-400 to-green-400', + 'bg-gradient-to-r from-green-400 to-teal-400', +] + +function FullPageTransition() { + let [activePage, setActivePage] = useState(0) + let previousPage = usePrevious(activePage) + + let direction = activePage > previousPage ? Direction.Forwards : Direction.Backwards + + let transitions = match(direction, { + [Direction.Forwards]: { + enter: 'transition transform ease-in-out duration-500', + enterFrom: 'translate-x-full', + enterTo: 'translate-x-0', + leave: 'transition transform ease-in-out duration-500', + leaveFrom: 'translate-x-0', + leaveTo: '-translate-x-full', + }, + [Direction.Backwards]: { + enter: 'transition transform ease-in-out duration-500', + enterFrom: '-translate-x-full', + enterTo: 'translate-x-0', + leave: 'transition transform ease-in-out duration-500', + leaveFrom: 'translate-x-0', + leaveTo: 'translate-x-full', + }, + }) + + return ( +
+
+ +
+
+

+ {pages[activePage]} +

+
+
+
+ +
+
+
+
+ {pages.map((page, i) => ( + + {page} page content + + ))} +
+
+
+
+
+ ) +} diff --git a/packages/playground-react/pages/transitions/full-page-examples/layout-with-sidebar.tsx b/packages/playground-react/pages/transitions/full-page-examples/layout-with-sidebar.tsx new file mode 100644 index 0000000000..48b0980bb9 --- /dev/null +++ b/packages/playground-react/pages/transitions/full-page-examples/layout-with-sidebar.tsx @@ -0,0 +1,170 @@ +import React, { useEffect, useState } from 'react' +import Head from 'next/head' +import { Transition } from '@headlessui/react' + +export default function App() { + let [mobileOpen, setMobileOpen] = useState(false) + + useEffect(() => { + function handleEscape(event) { + if (!mobileOpen) return + + if (event.key === 'Escape') { + setMobileOpen(false) + } + } + + document.addEventListener('keyup', handleEscape) + return () => document.removeEventListener('keyup', handleEscape) + }, [mobileOpen]) + + return ( + <> + + Transition Component - Layout with sidebar + + +
+ {/* Off-canvas menu for mobile */} + + {/* Off-canvas menu overlay, show/hide based on off-canvas menu state. */} + + {() => ( +
+
setMobileOpen(false)} + className="bg-cool-gray-600 absolute inset-0 opacity-75" + /> +
+ )} + + + {/* Off-canvas menu, show/hide based on off-canvas menu state. */} + +
+ setMobileOpen(false)} + > + + + + +
+
+ Easywire logo +
+
+
+ {/* Dummy element to force sidebar to shrink to fit close icon */} +
+ + + {/* Static sidebar for desktop */} +
+
+ {/* Sidebar component, swap this element with another sidebar if you like */} +
+
+ Easywire logo +
+
+
+
+
+
+ + {/* Search bar */} +
+
+
+ +
+
+ + + +
+ +
+
+
+
+
+
+ {/* Replace with your content */} +
+ {/* /End replace */} +
+
+
+ + ) +} diff --git a/packages/playground-react/public/favicon.ico b/packages/playground-react/public/favicon.ico new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/playground-react/tsconfig.json b/packages/playground-react/tsconfig.json new file mode 100644 index 0000000000..1563f3e878 --- /dev/null +++ b/packages/playground-react/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": false, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "incremental": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve" + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"] +} diff --git a/packages/playground-react/utils/class-names.ts b/packages/playground-react/utils/class-names.ts new file mode 100644 index 0000000000..159b03ce39 --- /dev/null +++ b/packages/playground-react/utils/class-names.ts @@ -0,0 +1,3 @@ +export function classNames(...classes: (false | null | undefined | string)[]): string { + return classes.filter(Boolean).join(' ') +} diff --git a/packages/playground-react/utils/hooks/use-popper.ts b/packages/playground-react/utils/hooks/use-popper.ts new file mode 100644 index 0000000000..61d3c14f79 --- /dev/null +++ b/packages/playground-react/utils/hooks/use-popper.ts @@ -0,0 +1,37 @@ +import { RefCallback, useRef, useCallback, useMemo } from 'react' +import { createPopper, Options } from '@popperjs/core' + +/** + * Example implementation to use Popper: https://popper.js.org/ + */ +export function usePopper( + options?: Partial +): [RefCallback, RefCallback] { + let reference = useRef(null) + let popper = useRef(null) + + let cleanupCallback = useRef(() => {}) + + let instantiatePopper = useCallback(() => { + if (!reference.current) return + if (!popper.current) return + + if (cleanupCallback.current) cleanupCallback.current() + + cleanupCallback.current = createPopper(reference.current, popper.current, options).destroy + }, [reference, popper, cleanupCallback, options]) + + return useMemo( + () => [ + (referenceDomNode) => { + reference.current = referenceDomNode + instantiatePopper() + }, + (popperDomNode) => { + popper.current = popperDomNode + instantiatePopper() + }, + ], + [reference, popper, instantiatePopper] + ) +} diff --git a/packages/playground-react/utils/match.ts b/packages/playground-react/utils/match.ts new file mode 100644 index 0000000000..c4becd32cd --- /dev/null +++ b/packages/playground-react/utils/match.ts @@ -0,0 +1,20 @@ +export function match( + value: TValue, + lookup: Record TReturnValue)>, + ...args: any[] +): TReturnValue { + if (value in lookup) { + let returnValue = lookup[value] + return typeof returnValue === 'function' ? returnValue(...args) : returnValue + } + + let error = new Error( + `Tried to handle "${value}" but there is no handler defined. Only defined handlers are: ${Object.keys( + lookup + ) + .map((key) => `"${key}"`) + .join(', ')}.` + ) + if (Error.captureStackTrace) Error.captureStackTrace(error, match) + throw error +} diff --git a/packages/playground-react/utils/resolve-all-examples.ts b/packages/playground-react/utils/resolve-all-examples.ts new file mode 100644 index 0000000000..328da9020f --- /dev/null +++ b/packages/playground-react/utils/resolve-all-examples.ts @@ -0,0 +1,50 @@ +import fs from 'fs' +import path from 'path' +export type ExamplesType = { + name: string + path: string + children?: ExamplesType[] +} + +export async function resolveAllExamples(...paths: string[]) { + let base = path.resolve(process.cwd(), ...paths) + + if (!fs.existsSync(base)) { + return false + } + + let files = await fs.promises.readdir(base, { withFileTypes: true }) + let items: ExamplesType[] = [] + + for (let file of files) { + if (file.name === '.DS_Store') { + continue + } + + // Skip reserved filenames from Next. E.g.: _app.tsx, _error.tsx + if (file.name.startsWith('_')) { + continue + } + + let bucket: ExamplesType = { + name: file.name.replace(/-/g, ' ').replace(/\.tsx?/g, ''), + path: [...paths, file.name] + .join('/') + .replace(/^pages/, '') + .replace(/\.tsx?/g, '') + .replace(/\/+/g, '/'), + } + + if (file.isDirectory()) { + let children = await resolveAllExamples(...paths, file.name) + + if (children) { + bucket.children = children + } + } + + items.push(bucket) + } + + return items +} diff --git a/packages/playground-vue/index.html b/packages/playground-vue/index.html new file mode 100644 index 0000000000..83ca364dc6 --- /dev/null +++ b/packages/playground-vue/index.html @@ -0,0 +1,15 @@ + + + + + + + Headless UI - Playground + + + + +
+ + + diff --git a/packages/playground-vue/package.json b/packages/playground-vue/package.json new file mode 100644 index 0000000000..ed66bc07aa --- /dev/null +++ b/packages/playground-vue/package.json @@ -0,0 +1,25 @@ +{ + "name": "playground-vue", + "private": true, + "version": "0.0.0", + "directories": { + "example": "examples" + }, + "scripts": { + "prebuild": "yarn workspace @headlessui/vue build", + "dev:headlessui": "yarn workspace @headlessui/vue watch", + "dev:next": "vite serve", + "dev": "npm-run-all -p dev:*", + "build": "NODE_ENV=production vite build", + "clean": "rimraf ./dist" + }, + "dependencies": { + "@headlessui/vue": "*", + "vue": "^3.2.27", + "vue-router": "^4.0.0" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^2.0.1", + "vite": "^2.7.13" + } +} diff --git a/packages/playground-vue/public/favicon.ico b/packages/playground-vue/public/favicon.ico new file mode 100644 index 0000000000..df36fcfb72 Binary files /dev/null and b/packages/playground-vue/public/favicon.ico differ diff --git a/packages/playground-vue/src/.generated/.gitignore b/packages/playground-vue/src/.generated/.gitignore new file mode 100644 index 0000000000..d6b7ef32c8 --- /dev/null +++ b/packages/playground-vue/src/.generated/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/packages/playground-vue/src/App.vue b/packages/playground-vue/src/App.vue new file mode 100644 index 0000000000..9e6dfa7f69 --- /dev/null +++ b/packages/playground-vue/src/App.vue @@ -0,0 +1,81 @@ + + + diff --git a/packages/playground-vue/src/KeyCaster.vue b/packages/playground-vue/src/KeyCaster.vue new file mode 100644 index 0000000000..b445ee94c6 --- /dev/null +++ b/packages/playground-vue/src/KeyCaster.vue @@ -0,0 +1,69 @@ + + + diff --git a/packages/playground-vue/src/components/Home.vue b/packages/playground-vue/src/components/Home.vue new file mode 100644 index 0000000000..cde352323d --- /dev/null +++ b/packages/playground-vue/src/components/Home.vue @@ -0,0 +1,46 @@ + + + diff --git a/packages/playground-vue/src/components/dialog/dialog.vue b/packages/playground-vue/src/components/dialog/dialog.vue new file mode 100644 index 0000000000..0fed689c9b --- /dev/null +++ b/packages/playground-vue/src/components/dialog/dialog.vue @@ -0,0 +1,242 @@ + + + diff --git a/packages/playground-vue/src/components/disclosure/disclosure.vue b/packages/playground-vue/src/components/disclosure/disclosure.vue new file mode 100644 index 0000000000..13afc0e05d --- /dev/null +++ b/packages/playground-vue/src/components/disclosure/disclosure.vue @@ -0,0 +1,33 @@ + + + diff --git a/packages/playground-vue/src/components/focus-trap/focus-trap.vue b/packages/playground-vue/src/components/focus-trap/focus-trap.vue new file mode 100644 index 0000000000..937578a67e --- /dev/null +++ b/packages/playground-vue/src/components/focus-trap/focus-trap.vue @@ -0,0 +1,27 @@ + + + diff --git a/packages/playground-vue/src/components/listbox/listbox.vue b/packages/playground-vue/src/components/listbox/listbox.vue new file mode 100644 index 0000000000..7269d90349 --- /dev/null +++ b/packages/playground-vue/src/components/listbox/listbox.vue @@ -0,0 +1,126 @@ + + + diff --git a/packages/playground-vue/src/components/listbox/multiple-elements.vue b/packages/playground-vue/src/components/listbox/multiple-elements.vue new file mode 100644 index 0000000000..ff5358469a --- /dev/null +++ b/packages/playground-vue/src/components/listbox/multiple-elements.vue @@ -0,0 +1,208 @@ + + + diff --git a/packages/playground-vue/src/components/menu/menu-with-popper.vue b/packages/playground-vue/src/components/menu/menu-with-popper.vue new file mode 100644 index 0000000000..4257c6841d --- /dev/null +++ b/packages/playground-vue/src/components/menu/menu-with-popper.vue @@ -0,0 +1,86 @@ + + + diff --git a/packages/playground-vue/src/components/menu/menu-with-transition-and-popper.vue b/packages/playground-vue/src/components/menu/menu-with-transition-and-popper.vue new file mode 100644 index 0000000000..bb5b186555 --- /dev/null +++ b/packages/playground-vue/src/components/menu/menu-with-transition-and-popper.vue @@ -0,0 +1,94 @@ + + + diff --git a/packages/playground-vue/src/components/menu/menu-with-transition.vue b/packages/playground-vue/src/components/menu/menu-with-transition.vue new file mode 100644 index 0000000000..cdcf742e83 --- /dev/null +++ b/packages/playground-vue/src/components/menu/menu-with-transition.vue @@ -0,0 +1,83 @@ + + + diff --git a/packages/playground-vue/src/components/menu/menu.vue b/packages/playground-vue/src/components/menu/menu.vue new file mode 100644 index 0000000000..5cb7cbd61a --- /dev/null +++ b/packages/playground-vue/src/components/menu/menu.vue @@ -0,0 +1,84 @@ + + + diff --git a/packages/playground-vue/src/components/menu/multiple-elements.vue b/packages/playground-vue/src/components/menu/multiple-elements.vue new file mode 100644 index 0000000000..eda326148c --- /dev/null +++ b/packages/playground-vue/src/components/menu/multiple-elements.vue @@ -0,0 +1,125 @@ + + + diff --git a/packages/playground-vue/src/components/popover/popover.vue b/packages/playground-vue/src/components/popover/popover.vue new file mode 100644 index 0000000000..082fd0a7ca --- /dev/null +++ b/packages/playground-vue/src/components/popover/popover.vue @@ -0,0 +1,144 @@ + + + diff --git a/packages/playground-vue/src/components/portal/portal.vue b/packages/playground-vue/src/components/portal/portal.vue new file mode 100644 index 0000000000..d96f2d41fe --- /dev/null +++ b/packages/playground-vue/src/components/portal/portal.vue @@ -0,0 +1,35 @@ + + + diff --git a/packages/playground-vue/src/components/radio-group/radio-group.vue b/packages/playground-vue/src/components/radio-group/radio-group.vue new file mode 100644 index 0000000000..5e9c1fb7b8 --- /dev/null +++ b/packages/playground-vue/src/components/radio-group/radio-group.vue @@ -0,0 +1,104 @@ + + + diff --git a/packages/playground-vue/src/components/switch/switch.vue b/packages/playground-vue/src/components/switch/switch.vue new file mode 100644 index 0000000000..93bdcb91f8 --- /dev/null +++ b/packages/playground-vue/src/components/switch/switch.vue @@ -0,0 +1,40 @@ + + + diff --git a/packages/playground-vue/src/components/tabs/tabs.vue b/packages/playground-vue/src/components/tabs/tabs.vue new file mode 100644 index 0000000000..d0048bbefb --- /dev/null +++ b/packages/playground-vue/src/components/tabs/tabs.vue @@ -0,0 +1,90 @@ + + + diff --git a/packages/playground-vue/src/main.js b/packages/playground-vue/src/main.js new file mode 100644 index 0000000000..3e79677c7c --- /dev/null +++ b/packages/playground-vue/src/main.js @@ -0,0 +1,5 @@ +import { createApp } from 'vue' +import App from './App.vue' +import router from './router' + +createApp(App).use(router).mount('#app') diff --git a/packages/playground-vue/src/playground-utils/hooks/use-popper.js b/packages/playground-vue/src/playground-utils/hooks/use-popper.js new file mode 100644 index 0000000000..3fe6c40fc3 --- /dev/null +++ b/packages/playground-vue/src/playground-utils/hooks/use-popper.js @@ -0,0 +1,26 @@ +import { ref, onMounted, watchEffect } from 'vue' +import { createPopper } from '@popperjs/core' + +export function usePopper(options) { + let reference = ref(null) + let popper = ref(null) + + onMounted(() => { + watchEffect((onInvalidate) => { + if (!popper.value) return + if (!reference.value) return + + let popperEl = popper.value.el || popper.value + let referenceEl = reference.value.el || reference.value + + if (!(referenceEl instanceof HTMLElement)) return + if (!(popperEl instanceof HTMLElement)) return + + let { destroy } = createPopper(referenceEl, popperEl, options) + + onInvalidate(destroy) + }) + }) + + return [reference, popper] +} diff --git a/packages/playground-vue/src/router.js b/packages/playground-vue/src/router.js new file mode 100644 index 0000000000..c32c50c7f5 --- /dev/null +++ b/packages/playground-vue/src/router.js @@ -0,0 +1,23 @@ +import { createWebHistory, createRouter, RouterView } from 'vue-router' +import lookup from './.generated/preload.js' +import routes from './routes.json' + +function buildRoutes(routes) { + return routes.map((route) => { + let definition = { + path: route.path, + component: route.component ? lookup[route.component] : RouterView, + } + + if (route.children) { + definition.children = buildRoutes(route.children) + } + + return definition + }) +} + +export default createRouter({ + history: createWebHistory(), + routes: buildRoutes(routes), +}) diff --git a/packages/playground-vue/src/routes.json b/packages/playground-vue/src/routes.json new file mode 100644 index 0000000000..d1f1408eb0 --- /dev/null +++ b/packages/playground-vue/src/routes.json @@ -0,0 +1,141 @@ +[ + { + "path": "/", + "component": "./components/Home.vue" + }, + { + "name": "Menu", + "path": "/menu", + "children": [ + { + "name": "Menu (basic)", + "path": "/menu/menu", + "component": "./components/menu/menu.vue" + }, + { + "name": "Menu with Popper", + "path": "/menu/menu-with-popper", + "component": "./components/menu/menu-with-popper.vue" + }, + { + "name": "Menu with Transition", + "path": "/menu/menu-with-transition", + "component": "./components/menu/menu-with-transition.vue" + }, + { + "name": "Menu with Popper + Transition", + "path": "/menu/menu-with-transition-and-popper", + "component": "./components/menu/menu-with-transition-and-popper.vue" + }, + { + "name": "Menu multiple elements", + "path": "/menu/multiple-elements", + "component": "./components/menu/multiple-elements.vue" + } + ] + }, + { + "name": "Listbox", + "path": "/listbox", + "children": [ + { + "name": "Listbox (basic)", + "path": "/listbox/listbox", + "component": "./components/listbox/listbox.vue" + }, + { + "name": "Listbox multiple elements", + "path": "/listbox/multiple-elements", + "component": "./components/listbox/multiple-elements.vue" + } + ] + }, + { + "name": "Switch", + "path": "/switch", + "children": [ + { + "name": "Switch (basic)", + "path": "/switch/switch", + "component": "./components/switch/switch.vue" + } + ] + }, + { + "name": "Tabs", + "path": "/tabs", + "children": [ + { + "name": "Tabs (basic)", + "path": "/tabs/tabs", + "component": "./components/tabs/tabs.vue" + } + ] + }, + { + "name": "Focus Trap", + "path": "/focus-trap", + "children": [ + { + "name": "FocusTrap (basic)", + "path": "/focus-trap/focus-trap", + "component": "./components/focus-trap/focus-trap.vue" + } + ] + }, + { + "name": "Portal", + "path": "/portal", + "children": [ + { + "name": "Portal (group)", + "path": "/portal/portal", + "component": "./components/portal/portal.vue" + } + ] + }, + { + "name": "Popover", + "path": "/popover", + "children": [ + { + "name": "Popover", + "path": "/popover/popover", + "component": "./components/popover/popover.vue" + } + ] + }, + { + "name": "Disclosure", + "path": "/disclosure", + "children": [ + { + "name": "Disclosure", + "path": "/disclosure/disclosure", + "component": "./components/disclosure/disclosure.vue" + } + ] + }, + { + "name": "Dialog", + "path": "/dialog", + "children": [ + { + "name": "Dialog", + "path": "/dialog/dialog", + "component": "./components/dialog/dialog.vue" + } + ] + }, + { + "name": "RadioGroup", + "path": "/radio-group", + "children": [ + { + "name": "RadioGroup", + "path": "/radio-group/radio-group", + "component": "./components/radio-group/radio-group.vue" + } + ] + } +] diff --git a/packages/@headlessui-vue/vercel.json b/packages/playground-vue/vercel.json similarity index 100% rename from packages/@headlessui-vue/vercel.json rename to packages/playground-vue/vercel.json diff --git a/packages/playground-vue/vite.config.js b/packages/playground-vue/vite.config.js new file mode 100644 index 0000000000..16068d10a1 --- /dev/null +++ b/packages/playground-vue/vite.config.js @@ -0,0 +1,32 @@ +import fs from 'fs' +import path from 'path' + +import vue from '@vitejs/plugin-vue' + +import routes from './src/routes.json' + +function flatten(routes, resolver) { + return routes + .map((route) => (route.children ? flatten(route.children, resolver) : resolver(route))) + .flat(Infinity) +} + +let map = {} +let contents = flatten(routes, (route) => route.component) + .map((path, i) => { + let name = `Component$${i + 1}` + map[path] = name + return `import ${name} from ".${path}";` + }) + .join('\n') + +let location = path.resolve(__dirname, './src/.generated/preload.js') +let data = `${contents}\n\nexport default {\n${Object.entries(map) + .map(([path, name]) => ` "${path}": ${name}`) + .join(',\n')}\n}` + +fs.writeFileSync(location, data, 'utf8') + +export default { + plugins: [vue()], +} diff --git a/scripts/build.sh b/scripts/build.sh index 3b74a9eb86..76c8b88e70 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -1,14 +1,33 @@ #!/bin/bash set -e -node="yarn node" -tsdxArgs=() +# Known variables +outdir="./dist" +name="headlessui" +input="./src/index.ts" -# Add script name -tsdxArgs+=("build" "--name" "headlessui" "--format" "cjs,esm,umd" "--tsconfig" "./tsconfig.tsdx.json") +# Find executables +esbuild=$(yarn bin esbuild) +tsc=$(yarn bin tsc) -# Passthrough arguments and flags -tsdxArgs+=($@) +# Setup shared options for esbuild +sharedOptions=() +sharedOptions+=("--bundle") +sharedOptions+=("--platform=browser") +sharedOptions+=("--target=es2020") + +# Generate actual builds +NODE_ENV=production $esbuild $input --format=esm --outfile=$outdir/$name.esm.js --minify ${sharedOptions[@]} $@ & +NODE_ENV=production $esbuild $input --format=cjs --outfile=$outdir/$name.prod.cjs.js --minify ${sharedOptions[@]} $@ & +NODE_ENV=production $esbuild $input --format=iife --outfile=$outdir/$name.iife.js --minify ${sharedOptions[@]} $@ & +NODE_ENV=development $esbuild $input --format=cjs --outfile=$outdir/$name.dev.cjs.js ${sharedOptions[@]} $@ & + +# Generate types +tsc --emitDeclarationOnly --outDir $outdir & + +# Copy build files over +cp -rf ./build/ $outdir + +# Wait for all the scripts to finish +wait -# Execute -$node "$(yarn bin tsdx)" "${tsdxArgs[@]}" diff --git a/scripts/lint.sh b/scripts/lint.sh index a547db9271..78270ebce6 100755 --- a/scripts/lint.sh +++ b/scripts/lint.sh @@ -10,19 +10,28 @@ RELATIVE_TARGET_DIR="${TARGET_DIR/$ROOT_DIR/}" pushd $ROOT_DIR > /dev/null -node="yarn node" -tsdxArgs=() +prettierArgs=() -# Add script name -tsdxArgs+=("lint") +if ! [ -z "$CI" ]; then + prettierArgs+=("--check") +else + prettierArgs+=("--write") + prettierArgs+=("$RELATIVE_TARGET_DIR") +fi # Add default arguments -tsdxArgs+=($RELATIVE_TARGET_DIR) +prettierArgs+=('--ignore-unknown') # Passthrough arguments and flags -tsdxArgs+=($@) +prettierArgs+=($@) + +# Ensure that a path is passed, otherwise default to the current directory +if [ -z "$@" ]; then + prettierArgs+=(.) +fi # Execute -$node "$(yarn bin tsdx)" "${tsdxArgs[@]}" +yarn prettier "${prettierArgs[@]}" popd > /dev/null + diff --git a/scripts/test.sh b/scripts/test.sh index 2032db2227..41a04526b1 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -8,7 +8,7 @@ jestArgs=() jestArgs+=("--passWithNoTests") # Add arguments based on environment variables -if [ -n "$CI" ]; then +if ! [ -z "$CI" ]; then jestArgs+=("--maxWorkers=4") jestArgs+=("--ci") fi @@ -18,3 +18,4 @@ jestArgs+=($@) # Execute $node "$(yarn bin jest)" "${jestArgs[@]}" + diff --git a/scripts/watch.sh b/scripts/watch.sh index 6a3b621070..4216be5179 100755 --- a/scripts/watch.sh +++ b/scripts/watch.sh @@ -1,14 +1,21 @@ #!/bin/bash set -e -node="yarn node" -tsdxArgs=() +# Known variables +outdir="./dist" +name="headlessui" +input="./src/index.ts" -# Add script name -tsdxArgs+=("watch" "--name" "headlessui" "--format" "cjs,esm,umd" "--tsconfig" "./tsconfig.tsdx.json") +# Find executables +esbuild=$(yarn bin esbuild) +tsc=$(yarn bin tsc) -# Passthrough arguments and flags -tsdxArgs+=($@) +# Setup shared options for esbuild +sharedOptions=() +sharedOptions+=("--bundle") +sharedOptions+=("--platform=browser") +sharedOptions+=("--target=es2020") + +# Generate actual builds +$esbuild $input --format=esm --outfile=$outdir/$name.esm.js --sourcemap ${sharedOptions[@]} $@ --watch -# Execute -$node "$(yarn bin tsdx)" "${tsdxArgs[@]}" diff --git a/yarn.lock b/yarn.lock index c693813338..beaa5b00ee 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,399 +2,162 @@ # yarn lockfile v1 -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== dependencies: "@babel/highlight" "^7.16.7" -"@babel/code-frame@^7.5.5": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a" - integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg== - dependencies: - "@babel/highlight" "^7.10.4" - -"@babel/compat-data@^7.10.4", "@babel/compat-data@^7.11.0": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.11.0.tgz#e9f73efe09af1355b723a7f39b11bad637d7c99c" - integrity sha512-TPSvJfv73ng0pfnEOh17bYMPQbI95+nGWc71Ss4vZdRBHTDqmM9Z8ZV4rYz8Ks7sfzc95n30k6ODIq5UGnXcYQ== - dependencies: - browserslist "^4.12.0" - invariant "^2.2.4" - semver "^5.5.0" - -"@babel/core@^7.1.0", "@babel/core@^7.4.4", "@babel/core@^7.7.5": - version "7.11.6" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.11.6.tgz#3a9455dc7387ff1bac45770650bc13ba04a15651" - integrity sha512-Wpcv03AGnmkgm6uS6k8iwhIwTrcP0m17TL1n1sy7qD0qelDu4XNeW0dN0mHfa+Gei211yDaLoEe/VlbXQzM4Bg== - dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/generator" "^7.11.6" - "@babel/helper-module-transforms" "^7.11.0" - "@babel/helpers" "^7.10.4" - "@babel/parser" "^7.11.5" - "@babel/template" "^7.10.4" - "@babel/traverse" "^7.11.5" - "@babel/types" "^7.11.5" +"@babel/compat-data@^7.16.4": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.16.8.tgz#31560f9f29fdf1868de8cb55049538a1b9732a60" + integrity sha512-m7OkX0IdKLKPpBlJtF561YJal5y/jyI5fNfWbPxh2D/nbzzGI4qRyrD8xO2jB24u7l+5I2a43scCG2IrfjC50Q== + +"@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.7.5": + version "7.16.10" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.16.10.tgz#ebd034f8e7ac2b6bfcdaa83a161141a646f74b50" + integrity sha512-pbiIdZbCiMx/MM6toR+OfXarYix3uz0oVsnNtfdAGTcCTu3w/JGF8JhirevXLBJUu0WguSZI12qpKnx7EeMyLA== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.16.8" + "@babel/helper-compilation-targets" "^7.16.7" + "@babel/helper-module-transforms" "^7.16.7" + "@babel/helpers" "^7.16.7" + "@babel/parser" "^7.16.10" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.16.10" + "@babel/types" "^7.16.8" convert-source-map "^1.7.0" debug "^4.1.0" - gensync "^1.0.0-beta.1" + gensync "^1.0.0-beta.2" json5 "^2.1.2" - lodash "^4.17.19" - resolve "^1.3.2" - semver "^5.4.1" + semver "^6.3.0" source-map "^0.5.0" -"@babel/generator@^7.11.5", "@babel/generator@^7.11.6": - version "7.11.6" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.11.6.tgz#b868900f81b163b4d464ea24545c61cbac4dc620" - integrity sha512-DWtQ1PV3r+cLbySoHrwn9RWEgKMBLLma4OBQloPRyDYvc5msJM9kvTLo1YnlJd1P/ZuKbdli3ijr5q3FvAF3uA== +"@babel/generator@^7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.16.8.tgz#359d44d966b8cd059d543250ce79596f792f2ebe" + integrity sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw== dependencies: - "@babel/types" "^7.11.5" + "@babel/types" "^7.16.8" jsesc "^2.5.1" source-map "^0.5.0" -"@babel/helper-annotate-as-pure@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz#5bf0d495a3f757ac3bda48b5bf3b3ba309c72ba3" - integrity sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA== - dependencies: - "@babel/types" "^7.10.4" - -"@babel/helper-builder-binary-assignment-operator-visitor@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz#bb0b75f31bf98cbf9ff143c1ae578b87274ae1a3" - integrity sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg== - dependencies: - "@babel/helper-explode-assignable-expression" "^7.10.4" - "@babel/types" "^7.10.4" - -"@babel/helper-compilation-targets@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.10.4.tgz#804ae8e3f04376607cc791b9d47d540276332bd2" - integrity sha512-a3rYhlsGV0UHNDvrtOXBg8/OpfV0OKTkxKPzIplS1zpx7CygDcWWxckxZeDd3gzPzC4kUT0A4nVFDK0wGMh4MQ== - dependencies: - "@babel/compat-data" "^7.10.4" - browserslist "^4.12.0" - invariant "^2.2.4" - levenary "^1.1.1" - semver "^5.5.0" - -"@babel/helper-create-class-features-plugin@^7.10.4": - version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.5.tgz#9f61446ba80e8240b0a5c85c6fdac8459d6f259d" - integrity sha512-0nkdeijB7VlZoLT3r/mY3bUkw3T8WG/hNw+FATs/6+pG2039IJWjTYL0VTISqsNHMUTEnwbVnc89WIJX9Qed0A== - dependencies: - "@babel/helper-function-name" "^7.10.4" - "@babel/helper-member-expression-to-functions" "^7.10.5" - "@babel/helper-optimise-call-expression" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/helper-replace-supers" "^7.10.4" - "@babel/helper-split-export-declaration" "^7.10.4" - -"@babel/helper-create-regexp-features-plugin@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.4.tgz#fdd60d88524659a0b6959c0579925e425714f3b8" - integrity sha512-2/hu58IEPKeoLF45DBwx3XFqsbCXmkdAay4spVr2x0jYgRxrSNp+ePwvSsy9g6YSaNDcKIQVPXk1Ov8S2edk2g== - dependencies: - "@babel/helper-annotate-as-pure" "^7.10.4" - "@babel/helper-regex" "^7.10.4" - regexpu-core "^4.7.0" - -"@babel/helper-define-map@^7.10.4": - version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.10.5.tgz#b53c10db78a640800152692b13393147acb9bb30" - integrity sha512-fMw4kgFB720aQFXSVaXr79pjjcW5puTCM16+rECJ/plGS+zByelE8l9nCpV1GibxTnFVmUuYG9U8wYfQHdzOEQ== - dependencies: - "@babel/helper-function-name" "^7.10.4" - "@babel/types" "^7.10.5" - lodash "^4.17.19" - -"@babel/helper-define-polyfill-provider@^0.0.3": - version "0.0.3" - resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.0.3.tgz#df9da66285b884ce66417abdd0b6ca91198149bd" - integrity sha512-dULDd/APiP4JowYDAMosecKOi/1v+UId99qhBGiO3myM29KtAVKS/R3x3OJJNBR0FeYB1BcYb2dCwkhqvxWXXQ== - dependencies: - "@babel/helper-compilation-targets" "^7.10.4" - "@babel/helper-module-imports" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/traverse" "^7.11.5" - debug "^4.1.1" - lodash.debounce "^4.0.8" - resolve "^1.14.2" - semver "^6.1.2" - -"@babel/helper-explode-assignable-expression@^7.10.4": - version "7.11.4" - resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.11.4.tgz#2d8e3470252cc17aba917ede7803d4a7a276a41b" - integrity sha512-ux9hm3zR4WV1Y3xXxXkdG/0gxF9nvI0YVmKVhvK9AfMoaQkemL3sJpXw+Xbz65azo8qJiEz2XVDUpK3KYhH3ZQ== - dependencies: - "@babel/types" "^7.10.4" - -"@babel/helper-function-name@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz#d2d3b20c59ad8c47112fa7d2a94bc09d5ef82f1a" - integrity sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ== - dependencies: - "@babel/helper-get-function-arity" "^7.10.4" - "@babel/template" "^7.10.4" - "@babel/types" "^7.10.4" - -"@babel/helper-get-function-arity@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz#98c1cbea0e2332f33f9a4661b8ce1505b2c19ba2" - integrity sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A== - dependencies: - "@babel/types" "^7.10.4" - -"@babel/helper-hoist-variables@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz#d49b001d1d5a68ca5e6604dda01a6297f7c9381e" - integrity sha512-wljroF5PgCk2juF69kanHVs6vrLwIPNp6DLD+Lrl3hoQ3PpPPikaDRNFA+0t81NOoMt2DL6WW/mdU8k4k6ZzuA== - dependencies: - "@babel/types" "^7.10.4" - -"@babel/helper-member-expression-to-functions@^7.10.4", "@babel/helper-member-expression-to-functions@^7.10.5": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.11.0.tgz#ae69c83d84ee82f4b42f96e2a09410935a8f26df" - integrity sha512-JbFlKHFntRV5qKw3YC0CvQnDZ4XMwgzzBbld7Ly4Mj4cbFy3KywcR8NtNctRToMWJOVvLINJv525Gd6wwVEx/Q== +"@babel/helper-compilation-targets@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz#06e66c5f299601e6c7da350049315e83209d551b" + integrity sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA== dependencies: - "@babel/types" "^7.11.0" + "@babel/compat-data" "^7.16.4" + "@babel/helper-validator-option" "^7.16.7" + browserslist "^4.17.5" + semver "^6.3.0" -"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz#4c5c54be04bd31670a7382797d75b9fa2e5b5620" - integrity sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw== +"@babel/helper-environment-visitor@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz#ff484094a839bde9d89cd63cba017d7aae80ecd7" + integrity sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag== dependencies: - "@babel/types" "^7.10.4" + "@babel/types" "^7.16.7" -"@babel/helper-module-transforms@^7.10.4", "@babel/helper-module-transforms@^7.10.5", "@babel/helper-module-transforms@^7.11.0": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz#b16f250229e47211abdd84b34b64737c2ab2d359" - integrity sha512-02EVu8COMuTRO1TAzdMtpBPbe6aQ1w/8fePD2YgQmxZU4gpNWaL9gK3Jp7dxlkUlUCJOTaSeA+Hrm1BRQwqIhg== +"@babel/helper-function-name@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz#f1ec51551fb1c8956bc8dd95f38523b6cf375f8f" + integrity sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA== dependencies: - "@babel/helper-module-imports" "^7.10.4" - "@babel/helper-replace-supers" "^7.10.4" - "@babel/helper-simple-access" "^7.10.4" - "@babel/helper-split-export-declaration" "^7.11.0" - "@babel/template" "^7.10.4" - "@babel/types" "^7.11.0" - lodash "^4.17.19" + "@babel/helper-get-function-arity" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/types" "^7.16.7" -"@babel/helper-optimise-call-expression@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz#50dc96413d594f995a77905905b05893cd779673" - integrity sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg== +"@babel/helper-get-function-arity@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz#ea08ac753117a669f1508ba06ebcc49156387419" + integrity sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw== dependencies: - "@babel/types" "^7.10.4" + "@babel/types" "^7.16.7" -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375" - integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg== - -"@babel/helper-regex@^7.10.4": - version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.10.5.tgz#32dfbb79899073c415557053a19bd055aae50ae0" - integrity sha512-68kdUAzDrljqBrio7DYAEgCoJHxppJOERHOgOrDN7WjOzP0ZQ1LsSDRXcemzVZaLvjaJsJEESb6qt+znNuENDg== +"@babel/helper-hoist-variables@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz#86bcb19a77a509c7b77d0e22323ef588fa58c246" + integrity sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg== dependencies: - lodash "^4.17.19" + "@babel/types" "^7.16.7" -"@babel/helper-remap-async-to-generator@^7.10.4": - version "7.11.4" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.11.4.tgz#4474ea9f7438f18575e30b0cac784045b402a12d" - integrity sha512-tR5vJ/vBa9wFy3m5LLv2faapJLnDFxNWff2SAYkSE4rLUdbp7CdObYFgI7wK4T/Mj4UzpjPwzR8Pzmr5m7MHGA== +"@babel/helper-module-imports@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437" + integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg== dependencies: - "@babel/helper-annotate-as-pure" "^7.10.4" - "@babel/helper-wrap-function" "^7.10.4" - "@babel/template" "^7.10.4" - "@babel/types" "^7.10.4" + "@babel/types" "^7.16.7" -"@babel/helper-replace-supers@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz#d585cd9388ea06e6031e4cd44b6713cbead9e6cf" - integrity sha512-sPxZfFXocEymYTdVK1UNmFPBN+Hv5mJkLPsYWwGBxZAxaWfFu+xqp7b6qWD0yjNuNL2VKc6L5M18tOXUP7NU0A== +"@babel/helper-module-transforms@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz#7665faeb721a01ca5327ddc6bba15a5cb34b6a41" + integrity sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng== dependencies: - "@babel/helper-member-expression-to-functions" "^7.10.4" - "@babel/helper-optimise-call-expression" "^7.10.4" - "@babel/traverse" "^7.10.4" - "@babel/types" "^7.10.4" + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-module-imports" "^7.16.7" + "@babel/helper-simple-access" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/helper-validator-identifier" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.16.7" + "@babel/types" "^7.16.7" -"@babel/helper-simple-access@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz#0f5ccda2945277a2a7a2d3a821e15395edcf3461" - integrity sha512-0fMy72ej/VEvF8ULmX6yb5MtHG4uH4Dbd6I/aHDb/JVg0bbivwt9Wg+h3uMvX+QSFtwr5MeItvazbrc4jtRAXw== - dependencies: - "@babel/template" "^7.10.4" - "@babel/types" "^7.10.4" +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.8.0": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz#aa3a8ab4c3cceff8e65eb9e73d87dc4ff320b2f5" + integrity sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA== -"@babel/helper-skip-transparent-expression-wrappers@^7.11.0": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.11.0.tgz#eec162f112c2f58d3af0af125e3bb57665146729" - integrity sha512-0XIdiQln4Elglgjbwo9wuJpL/K7AGCY26kmEt0+pRP0TAj4jjyNq1MjoRvikrTVqKcx4Gysxt4cXvVFXP/JO2Q== +"@babel/helper-simple-access@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz#d656654b9ea08dbb9659b69d61063ccd343ff0f7" + integrity sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g== dependencies: - "@babel/types" "^7.11.0" + "@babel/types" "^7.16.7" -"@babel/helper-split-export-declaration@^7.10.4", "@babel/helper-split-export-declaration@^7.11.0": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz#f8a491244acf6a676158ac42072911ba83ad099f" - integrity sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg== +"@babel/helper-split-export-declaration@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz#0b648c0c42da9d3920d85ad585f2778620b8726b" + integrity sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw== dependencies: - "@babel/types" "^7.11.0" + "@babel/types" "^7.16.7" -"@babel/helper-validator-identifier@^7.10.4", "@babel/helper-validator-identifier@^7.16.7": +"@babel/helper-validator-identifier@^7.14.9", "@babel/helper-validator-identifier@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== -"@babel/helper-wrap-function@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.10.4.tgz#8a6f701eab0ff39f765b5a1cfef409990e624b87" - integrity sha512-6py45WvEF0MhiLrdxtRjKjufwLL1/ob2qDJgg5JgNdojBAZSAKnAjkyOCNug6n+OBl4VW76XjvgSFTdaMcW0Ug== - dependencies: - "@babel/helper-function-name" "^7.10.4" - "@babel/template" "^7.10.4" - "@babel/traverse" "^7.10.4" - "@babel/types" "^7.10.4" +"@babel/helper-validator-option@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz#b203ce62ce5fe153899b617c08957de860de4d23" + integrity sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ== -"@babel/helpers@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.10.4.tgz#2abeb0d721aff7c0a97376b9e1f6f65d7a475044" - integrity sha512-L2gX/XeUONeEbI78dXSrJzGdz4GQ+ZTA/aazfUsFaWjSe95kiCuOZ5HsXvkiw3iwF+mFHSRUfJU8t6YavocdXA== +"@babel/helpers@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.16.7.tgz#7e3504d708d50344112767c3542fc5e357fffefc" + integrity sha512-9ZDoqtfY7AuEOt3cxchfii6C7GDyyMBffktR5B2jvWv8u2+efwvpnVKXMWzNehqy68tKgAfSwfdw/lWpthS2bw== dependencies: - "@babel/template" "^7.10.4" - "@babel/traverse" "^7.10.4" - "@babel/types" "^7.10.4" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.16.7" + "@babel/types" "^7.16.7" -"@babel/highlight@^7.10.4", "@babel/highlight@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.7.tgz#81a01d7d675046f0d96f82450d9d9578bdfd6b0b" - integrity sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw== +"@babel/highlight@^7.16.7": + version "7.16.10" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.10.tgz#744f2eb81579d6eea753c227b0f570ad785aba88" + integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw== dependencies: "@babel/helper-validator-identifier" "^7.16.7" chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.10.4", "@babel/parser@^7.11.5", "@babel/parser@^7.7.0": - version "7.11.5" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.11.5.tgz#c7ff6303df71080ec7a4f5b8c003c58f1cf51037" - integrity sha512-X9rD8qqm695vgmeaQ4fvz/o3+Wk4ZzQvSHkDBgpYKxpD4qTAUm88ZKtHkVqIOsYFFbIQ6wQYhC6q7pjqVK0E0Q== - -"@babel/parser@^7.12.0": - version "7.16.8" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.8.tgz#61c243a3875f7d0b0962b0543a33ece6ff2f1f17" - integrity sha512-i7jDUfrVBWc+7OKcBzEe5n7fbv3i2fWtxKzzCvOjnzSxMfWMigAhtfJ7qzZNGFNMsCCd67+uz553dYKWXPvCKw== - -"@babel/plugin-proposal-async-generator-functions@^7.10.4": - version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.10.5.tgz#3491cabf2f7c179ab820606cec27fed15e0e8558" - integrity sha512-cNMCVezQbrRGvXJwm9fu/1sJj9bHdGAgKodZdLqOQIpfoH3raqmRPBM17+lh7CzhiKRRBrGtZL9WcjxSoGYUSg== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/helper-remap-async-to-generator" "^7.10.4" - "@babel/plugin-syntax-async-generators" "^7.8.0" - -"@babel/plugin-proposal-class-properties@^7.10.4", "@babel/plugin-proposal-class-properties@^7.4.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.10.4.tgz#a33bf632da390a59c7a8c570045d1115cd778807" - integrity sha512-vhwkEROxzcHGNu2mzUC0OFFNXdZ4M23ib8aRRcJSsW8BZK9pQMD7QB7csl97NBbgGZO7ZyHUyKDnxzOaP4IrCg== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-proposal-dynamic-import@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.10.4.tgz#ba57a26cb98b37741e9d5bca1b8b0ddf8291f17e" - integrity sha512-up6oID1LeidOOASNXgv/CFbgBqTuKJ0cJjz6An5tWD+NVBNlp3VNSBxv2ZdU7SYl3NxJC7agAQDApZusV6uFwQ== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-syntax-dynamic-import" "^7.8.0" - -"@babel/plugin-proposal-export-namespace-from@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.10.4.tgz#570d883b91031637b3e2958eea3c438e62c05f54" - integrity sha512-aNdf0LY6/3WXkhh0Fdb6Zk9j1NMD8ovj3F6r0+3j837Pn1S1PdNtcwJ5EG9WkVPNHPxyJDaxMaAOVq4eki0qbg== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - -"@babel/plugin-proposal-json-strings@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.10.4.tgz#593e59c63528160233bd321b1aebe0820c2341db" - integrity sha512-fCL7QF0Jo83uy1K0P2YXrfX11tj3lkpN7l4dMv9Y9VkowkhkQDwFHFd8IiwyK5MZjE8UpbgokkgtcReH88Abaw== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-syntax-json-strings" "^7.8.0" - -"@babel/plugin-proposal-logical-assignment-operators@^7.11.0": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.11.0.tgz#9f80e482c03083c87125dee10026b58527ea20c8" - integrity sha512-/f8p4z+Auz0Uaf+i8Ekf1iM7wUNLcViFUGiPxKeXvxTSl63B875YPiVdUDdem7hREcI0E0kSpEhS8tF5RphK7Q== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" - -"@babel/plugin-proposal-nullish-coalescing-operator@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.10.4.tgz#02a7e961fc32e6d5b2db0649e01bf80ddee7e04a" - integrity sha512-wq5n1M3ZUlHl9sqT2ok1T2/MTt6AXE0e1Lz4WzWBr95LsAZ5qDXe4KnFuauYyEyLiohvXFMdbsOTMyLZs91Zlw== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" - -"@babel/plugin-proposal-numeric-separator@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.10.4.tgz#ce1590ff0a65ad12970a609d78855e9a4c1aef06" - integrity sha512-73/G7QoRoeNkLZFxsoCCvlg4ezE4eM+57PnOqgaPOozd5myfj7p0muD1mRVJvbUWbOzD+q3No2bWbaKy+DJ8DA== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" - -"@babel/plugin-proposal-object-rest-spread@^7.11.0": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.11.0.tgz#bd81f95a1f746760ea43b6c2d3d62b11790ad0af" - integrity sha512-wzch41N4yztwoRw0ak+37wxwJM2oiIiy6huGCoqkvSTA9acYWcPfn9Y4aJqmFFJ70KTJUu29f3DQ43uJ9HXzEA== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-syntax-object-rest-spread" "^7.8.0" - "@babel/plugin-transform-parameters" "^7.10.4" - -"@babel/plugin-proposal-optional-catch-binding@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.10.4.tgz#31c938309d24a78a49d68fdabffaa863758554dd" - integrity sha512-LflT6nPh+GK2MnFiKDyLiqSqVHkQnVf7hdoAvyTnnKj9xB3docGRsdPuxp6qqqW19ifK3xgc9U5/FwrSaCNX5g== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" - -"@babel/plugin-proposal-optional-chaining@^7.11.0": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.11.0.tgz#de5866d0646f6afdaab8a566382fe3a221755076" - integrity sha512-v9fZIu3Y8562RRwhm1BbMRxtqZNFmFA2EG+pT2diuU8PT3H6T/KXoZ54KgYisfOFZHV6PfvAiBIZ9Rcz+/JCxA== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/helper-skip-transparent-expression-wrappers" "^7.11.0" - "@babel/plugin-syntax-optional-chaining" "^7.8.0" - -"@babel/plugin-proposal-private-methods@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.10.4.tgz#b160d972b8fdba5c7d111a145fc8c421fc2a6909" - integrity sha512-wh5GJleuI8k3emgTg5KkJK6kHNsGEr0uBTDBuQUBJwckk9xs1ez79ioheEVVxMLyPscB0LfkbVHslQqIzWV6Bw== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-proposal-unicode-property-regex@^7.10.4", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.10.4.tgz#4483cda53041ce3413b7fe2f00022665ddfaa75d" - integrity sha512-H+3fOgPnEXFL9zGYtKQe4IDOPKYlZdF1kqFDQRRb8PK4B8af1vAGK04tF5iQAAsui+mHNBQSAtd2/ndEDe9wuA== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.16.10", "@babel/parser@^7.16.4", "@babel/parser@^7.16.7": + version "7.16.10" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.10.tgz#aba1b1cb9696a24a19f59c41af9cf17d1c716a88" + integrity sha512-Sm/S9Or6nN8uiFsQU1yodyDW3MWXQhFeqzMPM+t8MJjM+pLsnFVxFZzkpXKvUXh+Gz9cbMoYYs484+Jw/NTEFQ== -"@babel/plugin-syntax-async-generators@^7.8.0", "@babel/plugin-syntax-async-generators@^7.8.4": +"@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== @@ -408,26 +171,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-class-properties@^7.10.4", "@babel/plugin-syntax-class-properties@^7.8.3": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.10.4.tgz#6644e6a0baa55a61f9e3231f6c9eeb6ee46c124c" - integrity sha512-GCSBF7iUle6rNugfURwNmCGG3Z/2+opxAMLs1nND4bhEG5PuxTIggDBoeYYSujAlLtsupzOHYJQgPS3pivwXIA== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-dynamic-import@^7.8.0": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" - integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-export-namespace-from@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" - integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== +"@babel/plugin-syntax-class-properties@^7.8.3": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== dependencies: - "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-plugin-utils" "^7.12.13" "@babel/plugin-syntax-import-meta@^7.8.3": version "7.10.4" @@ -436,397 +185,68 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-syntax-json-strings@^7.8.0", "@babel/plugin-syntax-json-strings@^7.8.3": +"@babel/plugin-syntax-json-strings@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": +"@babel/plugin-syntax-jsx@7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.14.5.tgz#000e2e25d8673cce49300517a3eda44c263e4201" + integrity sha512-ohuFIsOMXJnbOMRfX7/w7LocdR6R7whhuRD4ax8IipLcLPlZGJKkBxgHp++U4N/vKyU16/YDQr2f5seajD3jIw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.0", "@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-numeric-separator@^7.10.4", "@babel/plugin-syntax-numeric-separator@^7.8.3": +"@babel/plugin-syntax-numeric-separator@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-syntax-object-rest-spread@^7.8.0", "@babel/plugin-syntax-object-rest-spread@^7.8.3": +"@babel/plugin-syntax-object-rest-spread@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-optional-catch-binding@^7.8.0", "@babel/plugin-syntax-optional-catch-binding@^7.8.3": +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-optional-chaining@^7.8.0", "@babel/plugin-syntax-optional-chaining@^7.8.3": +"@babel/plugin-syntax-optional-chaining@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-top-level-await@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.10.4.tgz#4bbeb8917b54fcf768364e0a81f560e33a3ef57d" - integrity sha512-ni1brg4lXEmWyafKr0ccFWkJG0CeMt4WV1oyeBW6EFObF4oOHclbkj5cARxAPQyAQ2UTuplJyK4nfkXIMMFvsQ== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-transform-arrow-functions@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.10.4.tgz#e22960d77e697c74f41c501d44d73dbf8a6a64cd" - integrity sha512-9J/oD1jV0ZCBcgnoFWFq1vJd4msoKb/TCpGNFyyLt0zABdcvgK3aYikZ8HjzB14c26bc7E3Q1yugpwGy2aTPNA== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-transform-async-to-generator@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.10.4.tgz#41a5017e49eb6f3cda9392a51eef29405b245a37" - integrity sha512-F6nREOan7J5UXTLsDsZG3DXmZSVofr2tGNwfdrVwkDWHfQckbQXnXSPfD7iO+c/2HGqycwyLST3DnZ16n+cBJQ== +"@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== dependencies: - "@babel/helper-module-imports" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/helper-remap-async-to-generator" "^7.10.4" - -"@babel/plugin-transform-block-scoped-functions@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.10.4.tgz#1afa595744f75e43a91af73b0d998ecfe4ebc2e8" - integrity sha512-WzXDarQXYYfjaV1szJvN3AD7rZgZzC1JtjJZ8dMHUyiK8mxPRahynp14zzNjU3VkPqPsO38CzxiWO1c9ARZ8JA== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-transform-block-scoping@^7.10.4": - version "7.11.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.11.1.tgz#5b7efe98852bef8d652c0b28144cd93a9e4b5215" - integrity sha512-00dYeDE0EVEHuuM+26+0w/SCL0BH2Qy7LwHuI4Hi4MH5gkC8/AqMN5uWFJIsoXZrAphiMm1iXzBw6L2T+eA0ew== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-transform-classes@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.10.4.tgz#405136af2b3e218bc4a1926228bc917ab1a0adc7" - integrity sha512-2oZ9qLjt161dn1ZE0Ms66xBncQH4In8Sqw1YWgBUZuGVJJS5c0OFZXL6dP2MRHrkU/eKhWg8CzFJhRQl50rQxA== - dependencies: - "@babel/helper-annotate-as-pure" "^7.10.4" - "@babel/helper-define-map" "^7.10.4" - "@babel/helper-function-name" "^7.10.4" - "@babel/helper-optimise-call-expression" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/helper-replace-supers" "^7.10.4" - "@babel/helper-split-export-declaration" "^7.10.4" - globals "^11.1.0" - -"@babel/plugin-transform-computed-properties@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.10.4.tgz#9ded83a816e82ded28d52d4b4ecbdd810cdfc0eb" - integrity sha512-JFwVDXcP/hM/TbyzGq3l/XWGut7p46Z3QvqFMXTfk6/09m7xZHJUN9xHfsv7vqqD4YnfI5ueYdSJtXqqBLyjBw== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-transform-destructuring@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.10.4.tgz#70ddd2b3d1bea83d01509e9bb25ddb3a74fc85e5" - integrity sha512-+WmfvyfsyF603iPa6825mq6Qrb7uLjTOsa3XOFzlYcYDHSS4QmpOWOL0NNBY5qMbvrcf3tq0Cw+v4lxswOBpgA== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-transform-dotall-regex@^7.10.4", "@babel/plugin-transform-dotall-regex@^7.4.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.10.4.tgz#469c2062105c1eb6a040eaf4fac4b488078395ee" - integrity sha512-ZEAVvUTCMlMFAbASYSVQoxIbHm2OkG2MseW6bV2JjIygOjdVv8tuxrCTzj1+Rynh7ODb8GivUy7dzEXzEhuPaA== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-transform-duplicate-keys@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.10.4.tgz#697e50c9fee14380fe843d1f306b295617431e47" - integrity sha512-GL0/fJnmgMclHiBTTWXNlYjYsA7rDrtsazHG6mglaGSTh0KsrW04qml+Bbz9FL0LcJIRwBWL5ZqlNHKTkU3xAA== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-transform-exponentiation-operator@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.10.4.tgz#5ae338c57f8cf4001bdb35607ae66b92d665af2e" - integrity sha512-S5HgLVgkBcRdyQAHbKj+7KyuWx8C6t5oETmUuwz1pt3WTWJhsUV0WIIXuVvfXMxl/QQyHKlSCNNtaIamG8fysw== - dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-transform-for-of@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.10.4.tgz#c08892e8819d3a5db29031b115af511dbbfebae9" - integrity sha512-ItdQfAzu9AlEqmusA/65TqJ79eRcgGmpPPFvBnGILXZH975G0LNjP1yjHvGgfuCxqrPPueXOPe+FsvxmxKiHHQ== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-transform-function-name@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.10.4.tgz#6a467880e0fc9638514ba369111811ddbe2644b7" - integrity sha512-OcDCq2y5+E0dVD5MagT5X+yTRbcvFjDI2ZVAottGH6tzqjx/LKpgkUepu3hp/u4tZBzxxpNGwLsAvGBvQ2mJzg== - dependencies: - "@babel/helper-function-name" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-transform-literals@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.10.4.tgz#9f42ba0841100a135f22712d0e391c462f571f3c" - integrity sha512-Xd/dFSTEVuUWnyZiMu76/InZxLTYilOSr1UlHV+p115Z/Le2Fi1KXkJUYz0b42DfndostYlPub3m8ZTQlMaiqQ== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-transform-member-expression-literals@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.10.4.tgz#b1ec44fcf195afcb8db2c62cd8e551c881baf8b7" - integrity sha512-0bFOvPyAoTBhtcJLr9VcwZqKmSjFml1iVxvPL0ReomGU53CX53HsM4h2SzckNdkQcHox1bpAqzxBI1Y09LlBSw== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-transform-modules-amd@^7.10.4": - version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.10.5.tgz#1b9cddaf05d9e88b3aad339cb3e445c4f020a9b1" - integrity sha512-elm5uruNio7CTLFItVC/rIzKLfQ17+fX7EVz5W0TMgIHFo1zY0Ozzx+lgwhL4plzl8OzVn6Qasx5DeEFyoNiRw== - dependencies: - "@babel/helper-module-transforms" "^7.10.5" - "@babel/helper-plugin-utils" "^7.10.4" - babel-plugin-dynamic-import-node "^2.3.3" - -"@babel/plugin-transform-modules-commonjs@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.10.4.tgz#66667c3eeda1ebf7896d41f1f16b17105a2fbca0" - integrity sha512-Xj7Uq5o80HDLlW64rVfDBhao6OX89HKUmb+9vWYaLXBZOma4gA6tw4Ni1O5qVDoZWUV0fxMYA0aYzOawz0l+1w== - dependencies: - "@babel/helper-module-transforms" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/helper-simple-access" "^7.10.4" - babel-plugin-dynamic-import-node "^2.3.3" - -"@babel/plugin-transform-modules-systemjs@^7.10.4": - version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.10.5.tgz#6270099c854066681bae9e05f87e1b9cadbe8c85" - integrity sha512-f4RLO/OL14/FP1AEbcsWMzpbUz6tssRaeQg11RH1BP/XnPpRoVwgeYViMFacnkaw4k4wjRSjn3ip1Uw9TaXuMw== - dependencies: - "@babel/helper-hoist-variables" "^7.10.4" - "@babel/helper-module-transforms" "^7.10.5" - "@babel/helper-plugin-utils" "^7.10.4" - babel-plugin-dynamic-import-node "^2.3.3" - -"@babel/plugin-transform-modules-umd@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.10.4.tgz#9a8481fe81b824654b3a0b65da3df89f3d21839e" - integrity sha512-mohW5q3uAEt8T45YT7Qc5ws6mWgJAaL/8BfWD9Dodo1A3RKWli8wTS+WiQ/knF+tXlPirW/1/MqzzGfCExKECA== - dependencies: - "@babel/helper-module-transforms" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-transform-named-capturing-groups-regex@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.10.4.tgz#78b4d978810b6f3bcf03f9e318f2fc0ed41aecb6" - integrity sha512-V6LuOnD31kTkxQPhKiVYzYC/Jgdq53irJC/xBSmqcNcqFGV+PER4l6rU5SH2Vl7bH9mLDHcc0+l9HUOe4RNGKA== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.10.4" - -"@babel/plugin-transform-new-target@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.10.4.tgz#9097d753cb7b024cb7381a3b2e52e9513a9c6888" - integrity sha512-YXwWUDAH/J6dlfwqlWsztI2Puz1NtUAubXhOPLQ5gjR/qmQ5U96DY4FQO8At33JN4XPBhrjB8I4eMmLROjjLjw== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-transform-object-super@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.10.4.tgz#d7146c4d139433e7a6526f888c667e314a093894" - integrity sha512-5iTw0JkdRdJvr7sY0vHqTpnruUpTea32JHmq/atIWqsnNussbRzjEDyWep8UNztt1B5IusBYg8Irb0bLbiEBCQ== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/helper-replace-supers" "^7.10.4" - -"@babel/plugin-transform-parameters@^7.10.4": - version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.10.5.tgz#59d339d58d0b1950435f4043e74e2510005e2c4a" - integrity sha512-xPHwUj5RdFV8l1wuYiu5S9fqWGM2DrYc24TMvUiRrPVm+SM3XeqU9BcokQX/kEUe+p2RBwy+yoiR1w/Blq6ubw== - dependencies: - "@babel/helper-get-function-arity" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-transform-property-literals@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.10.4.tgz#f6fe54b6590352298785b83edd815d214c42e3c0" - integrity sha512-ofsAcKiUxQ8TY4sScgsGeR2vJIsfrzqvFb9GvJ5UdXDzl+MyYCaBj/FGzXuv7qE0aJcjWMILny1epqelnFlz8g== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-transform-regenerator@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.10.4.tgz#2015e59d839074e76838de2159db421966fd8b63" - integrity sha512-3thAHwtor39A7C04XucbMg17RcZ3Qppfxr22wYzZNcVIkPHfpM9J0SO8zuCV6SZa265kxBJSrfKTvDCYqBFXGw== - dependencies: - regenerator-transform "^0.14.2" - -"@babel/plugin-transform-reserved-words@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.10.4.tgz#8f2682bcdcef9ed327e1b0861585d7013f8a54dd" - integrity sha512-hGsw1O6Rew1fkFbDImZIEqA8GoidwTAilwCyWqLBM9f+e/u/sQMQu7uX6dyokfOayRuuVfKOW4O7HvaBWM+JlQ== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-transform-shorthand-properties@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.10.4.tgz#9fd25ec5cdd555bb7f473e5e6ee1c971eede4dd6" - integrity sha512-AC2K/t7o07KeTIxMoHneyX90v3zkm5cjHJEokrPEAGEy3UCp8sLKfnfOIGdZ194fyN4wfX/zZUWT9trJZ0qc+Q== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-transform-spread@^7.11.0": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.11.0.tgz#fa84d300f5e4f57752fe41a6d1b3c554f13f17cc" - integrity sha512-UwQYGOqIdQJe4aWNyS7noqAnN2VbaczPLiEtln+zPowRNlD+79w3oi2TWfYe0eZgd+gjZCbsydN7lzWysDt+gw== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/helper-skip-transparent-expression-wrappers" "^7.11.0" - -"@babel/plugin-transform-sticky-regex@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.10.4.tgz#8f3889ee8657581130a29d9cc91d7c73b7c4a28d" - integrity sha512-Ddy3QZfIbEV0VYcVtFDCjeE4xwVTJWTmUtorAJkn6u/92Z/nWJNV+mILyqHKrUxXYKA2EoCilgoPePymKL4DvQ== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/helper-regex" "^7.10.4" - -"@babel/plugin-transform-template-literals@^7.10.4": - version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.10.5.tgz#78bc5d626a6642db3312d9d0f001f5e7639fde8c" - integrity sha512-V/lnPGIb+KT12OQikDvgSuesRX14ck5FfJXt6+tXhdkJ+Vsd0lDCVtF6jcB4rNClYFzaB2jusZ+lNISDk2mMMw== - dependencies: - "@babel/helper-annotate-as-pure" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-transform-typeof-symbol@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.10.4.tgz#9509f1a7eec31c4edbffe137c16cc33ff0bc5bfc" - integrity sha512-QqNgYwuuW0y0H+kUE/GWSR45t/ccRhe14Fs/4ZRouNNQsyd4o3PG4OtHiIrepbM2WKUBDAXKCAK/Lk4VhzTaGA== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-transform-unicode-escapes@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.10.4.tgz#feae523391c7651ddac115dae0a9d06857892007" - integrity sha512-y5XJ9waMti2J+e7ij20e+aH+fho7Wb7W8rNuu72aKRwCHFqQdhkdU2lo3uZ9tQuboEJcUFayXdARhcxLQ3+6Fg== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-transform-unicode-regex@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.10.4.tgz#e56d71f9282fac6db09c82742055576d5e6d80a8" - integrity sha512-wNfsc4s8N2qnIwpO/WP2ZiSyjfpTamT2C9V9FDH/Ljub9zw6P3SjkXcFmc0RQUt96k2fmIvtla2MMjgTwIAC+A== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/preset-env@^7.11.0": - version "7.11.5" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.11.5.tgz#18cb4b9379e3e92ffea92c07471a99a2914e4272" - integrity sha512-kXqmW1jVcnB2cdueV+fyBM8estd5mlNfaQi6lwLgRwCby4edpavgbFhiBNjmWA3JpB/yZGSISa7Srf+TwxDQoA== - dependencies: - "@babel/compat-data" "^7.11.0" - "@babel/helper-compilation-targets" "^7.10.4" - "@babel/helper-module-imports" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-proposal-async-generator-functions" "^7.10.4" - "@babel/plugin-proposal-class-properties" "^7.10.4" - "@babel/plugin-proposal-dynamic-import" "^7.10.4" - "@babel/plugin-proposal-export-namespace-from" "^7.10.4" - "@babel/plugin-proposal-json-strings" "^7.10.4" - "@babel/plugin-proposal-logical-assignment-operators" "^7.11.0" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.10.4" - "@babel/plugin-proposal-numeric-separator" "^7.10.4" - "@babel/plugin-proposal-object-rest-spread" "^7.11.0" - "@babel/plugin-proposal-optional-catch-binding" "^7.10.4" - "@babel/plugin-proposal-optional-chaining" "^7.11.0" - "@babel/plugin-proposal-private-methods" "^7.10.4" - "@babel/plugin-proposal-unicode-property-regex" "^7.10.4" - "@babel/plugin-syntax-async-generators" "^7.8.0" - "@babel/plugin-syntax-class-properties" "^7.10.4" - "@babel/plugin-syntax-dynamic-import" "^7.8.0" - "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - "@babel/plugin-syntax-json-strings" "^7.8.0" - "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" - "@babel/plugin-syntax-object-rest-spread" "^7.8.0" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" - "@babel/plugin-syntax-optional-chaining" "^7.8.0" - "@babel/plugin-syntax-top-level-await" "^7.10.4" - "@babel/plugin-transform-arrow-functions" "^7.10.4" - "@babel/plugin-transform-async-to-generator" "^7.10.4" - "@babel/plugin-transform-block-scoped-functions" "^7.10.4" - "@babel/plugin-transform-block-scoping" "^7.10.4" - "@babel/plugin-transform-classes" "^7.10.4" - "@babel/plugin-transform-computed-properties" "^7.10.4" - "@babel/plugin-transform-destructuring" "^7.10.4" - "@babel/plugin-transform-dotall-regex" "^7.10.4" - "@babel/plugin-transform-duplicate-keys" "^7.10.4" - "@babel/plugin-transform-exponentiation-operator" "^7.10.4" - "@babel/plugin-transform-for-of" "^7.10.4" - "@babel/plugin-transform-function-name" "^7.10.4" - "@babel/plugin-transform-literals" "^7.10.4" - "@babel/plugin-transform-member-expression-literals" "^7.10.4" - "@babel/plugin-transform-modules-amd" "^7.10.4" - "@babel/plugin-transform-modules-commonjs" "^7.10.4" - "@babel/plugin-transform-modules-systemjs" "^7.10.4" - "@babel/plugin-transform-modules-umd" "^7.10.4" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.10.4" - "@babel/plugin-transform-new-target" "^7.10.4" - "@babel/plugin-transform-object-super" "^7.10.4" - "@babel/plugin-transform-parameters" "^7.10.4" - "@babel/plugin-transform-property-literals" "^7.10.4" - "@babel/plugin-transform-regenerator" "^7.10.4" - "@babel/plugin-transform-reserved-words" "^7.10.4" - "@babel/plugin-transform-shorthand-properties" "^7.10.4" - "@babel/plugin-transform-spread" "^7.11.0" - "@babel/plugin-transform-sticky-regex" "^7.10.4" - "@babel/plugin-transform-template-literals" "^7.10.4" - "@babel/plugin-transform-typeof-symbol" "^7.10.4" - "@babel/plugin-transform-unicode-escapes" "^7.10.4" - "@babel/plugin-transform-unicode-regex" "^7.10.4" - "@babel/preset-modules" "^0.1.3" - "@babel/types" "^7.11.5" - browserslist "^4.12.0" - core-js-compat "^3.6.2" - invariant "^2.2.2" - levenary "^1.1.1" - semver "^5.5.0" - -"@babel/preset-modules@^0.1.3": - version "0.1.4" - resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.4.tgz#362f2b68c662842970fdb5e254ffc8fc1c2e415e" - integrity sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" - "@babel/plugin-transform-dotall-regex" "^7.4.4" - "@babel/types" "^7.4.4" - esutils "^2.0.2" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/runtime-corejs3@^7.10.2": version "7.16.8" @@ -843,47 +263,40 @@ dependencies: regenerator-runtime "^0.13.4" -"@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4": - version "7.11.2" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736" - integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw== - dependencies: - regenerator-runtime "^0.13.4" - -"@babel/template@^7.10.4", "@babel/template@^7.3.3": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278" - integrity sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA== - dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/parser" "^7.10.4" - "@babel/types" "^7.10.4" - -"@babel/traverse@^7.1.0", "@babel/traverse@^7.10.4", "@babel/traverse@^7.11.5", "@babel/traverse@^7.7.0": - version "7.11.5" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.11.5.tgz#be777b93b518eb6d76ee2e1ea1d143daa11e61c3" - integrity sha512-EjiPXt+r7LiCZXEfRpSJd+jUMnBd4/9OUv7Nx3+0u9+eimMwJmG0Q98lw4/289JCoxSE8OolDMNZaaF/JZ69WQ== - dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/generator" "^7.11.5" - "@babel/helper-function-name" "^7.10.4" - "@babel/helper-split-export-declaration" "^7.11.0" - "@babel/parser" "^7.11.5" - "@babel/types" "^7.11.5" +"@babel/template@^7.16.7", "@babel/template@^7.3.3": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" + integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/parser" "^7.16.7" + "@babel/types" "^7.16.7" + +"@babel/traverse@^7.1.0", "@babel/traverse@^7.16.10", "@babel/traverse@^7.16.7": + version "7.16.10" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.16.10.tgz#448f940defbe95b5a8029975b051f75993e8239f" + integrity sha512-yzuaYXoRJBGMlBhsMJoUW7G1UmSb/eXr/JHYM/MsOJgavJibLwASijW7oXBdw3NQ6T0bW7Ty5P/VarOs9cHmqw== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.16.8" + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-function-name" "^7.16.7" + "@babel/helper-hoist-variables" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/parser" "^7.16.10" + "@babel/types" "^7.16.8" debug "^4.1.0" globals "^11.1.0" - lodash "^4.17.19" -"@babel/types@^7.0.0", "@babel/types@^7.10.4", "@babel/types@^7.10.5", "@babel/types@^7.11.0", "@babel/types@^7.11.5", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.7.0": - version "7.11.5" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.11.5.tgz#d9de577d01252d77c6800cee039ee64faf75662d" - integrity sha512-bvM7Qz6eKnJVFIn+1LPtjlBFPVN5jNDc1XmN15vWe7Q3DPBufWWsLiIvUu7xW87uTG6QoggpIDnUgLQvPheU+Q== +"@babel/types@7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.15.0.tgz#61af11f2286c4e9c69ca8deb5f4375a73c72dcbd" + integrity sha512-OBvfqnllOIdX4ojTHpwZbpvz4j3EWyjkZEdmjH0/cgsd6QOdSgU8rLSk6ard/pcW7rlmjdVSX/AWOaORR1uNOQ== dependencies: - "@babel/helper-validator-identifier" "^7.10.4" - lodash "^4.17.19" + "@babel/helper-validator-identifier" "^7.14.9" to-fast-properties "^2.0.0" -"@babel/types@^7.12.0": +"@babel/types@^7.0.0", "@babel/types@^7.16.7", "@babel/types@^7.16.8", "@babel/types@^7.3.0", "@babel/types@^7.3.3": version "7.16.8" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.8.tgz#0ba5da91dd71e0a4e7781a30f22770831062e3c1" integrity sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg== @@ -904,6 +317,18 @@ exec-sh "^0.3.2" minimist "^1.2.0" +"@emotion/is-prop-valid@^0.8.2": + version "0.8.8" + resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz#db28b1c4368a259b60a97311d6a952d4fd01ac1a" + integrity sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA== + dependencies: + "@emotion/memoize" "0.7.4" + +"@emotion/memoize@0.7.4": + version "0.7.4" + resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb" + integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw== + "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" @@ -916,179 +341,178 @@ resolve-from "^5.0.0" "@istanbuljs/schema@^0.1.2": - version "0.1.2" - resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" - integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw== + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== -"@jest/console@^25.5.0": - version "25.5.0" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-25.5.0.tgz#770800799d510f37329c508a9edd0b7b447d9abb" - integrity sha512-T48kZa6MK1Y6k4b89sexwmSF4YLeZS/Udqg3Jj3jG/cHH+N/sLFCEoXEDMOKugJQ9FxPN1osxIknvKkxt6MKyw== +"@jest/console@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-26.6.2.tgz#4e04bc464014358b03ab4937805ee36a0aeb98f2" + integrity sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g== dependencies: - "@jest/types" "^25.5.0" - chalk "^3.0.0" - jest-message-util "^25.5.0" - jest-util "^25.5.0" + "@jest/types" "^26.6.2" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^26.6.2" + jest-util "^26.6.2" slash "^3.0.0" -"@jest/core@^25.5.4": - version "25.5.4" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-25.5.4.tgz#3ef7412f7339210f003cdf36646bbca786efe7b4" - integrity sha512-3uSo7laYxF00Dg/DMgbn4xMJKmDdWvZnf89n8Xj/5/AeQ2dOQmn6b6Hkj/MleyzZWXpwv+WSdYWl4cLsy2JsoA== +"@jest/core@^26.6.3": + version "26.6.3" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-26.6.3.tgz#7639fcb3833d748a4656ada54bde193051e45fad" + integrity sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw== dependencies: - "@jest/console" "^25.5.0" - "@jest/reporters" "^25.5.1" - "@jest/test-result" "^25.5.0" - "@jest/transform" "^25.5.1" - "@jest/types" "^25.5.0" + "@jest/console" "^26.6.2" + "@jest/reporters" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/transform" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" ansi-escapes "^4.2.1" - chalk "^3.0.0" + chalk "^4.0.0" exit "^0.1.2" graceful-fs "^4.2.4" - jest-changed-files "^25.5.0" - jest-config "^25.5.4" - jest-haste-map "^25.5.1" - jest-message-util "^25.5.0" - jest-regex-util "^25.2.6" - jest-resolve "^25.5.1" - jest-resolve-dependencies "^25.5.4" - jest-runner "^25.5.4" - jest-runtime "^25.5.4" - jest-snapshot "^25.5.1" - jest-util "^25.5.0" - jest-validate "^25.5.0" - jest-watcher "^25.5.0" + jest-changed-files "^26.6.2" + jest-config "^26.6.3" + jest-haste-map "^26.6.2" + jest-message-util "^26.6.2" + jest-regex-util "^26.0.0" + jest-resolve "^26.6.2" + jest-resolve-dependencies "^26.6.3" + jest-runner "^26.6.3" + jest-runtime "^26.6.3" + jest-snapshot "^26.6.2" + jest-util "^26.6.2" + jest-validate "^26.6.2" + jest-watcher "^26.6.2" micromatch "^4.0.2" p-each-series "^2.1.0" - realpath-native "^2.0.0" rimraf "^3.0.0" slash "^3.0.0" strip-ansi "^6.0.0" -"@jest/environment@^25.5.0": - version "25.5.0" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-25.5.0.tgz#aa33b0c21a716c65686638e7ef816c0e3a0c7b37" - integrity sha512-U2VXPEqL07E/V7pSZMSQCvV5Ea4lqOlT+0ZFijl/i316cRMHvZ4qC+jBdryd+lmRetjQo0YIQr6cVPNxxK87mA== +"@jest/create-cache-key-function@^27.4.2": + version "27.4.2" + resolved "https://registry.yarnpkg.com/@jest/create-cache-key-function/-/create-cache-key-function-27.4.2.tgz#09b585f9dbafec0f56cfb0e4d4edfe2bec0e0768" + integrity sha512-aSSCAJwUNX4R1hJQoyimsND5l+2EsFgzlepS8NuOJJHjXij/UdxYFngac44tmv9IYdI+kglAyORg0plt4/aFMQ== + dependencies: + "@jest/types" "^27.4.2" + +"@jest/environment@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-26.6.2.tgz#ba364cc72e221e79cc8f0a99555bf5d7577cf92c" + integrity sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA== dependencies: - "@jest/fake-timers" "^25.5.0" - "@jest/types" "^25.5.0" - jest-mock "^25.5.0" + "@jest/fake-timers" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + jest-mock "^26.6.2" -"@jest/fake-timers@^25.5.0": - version "25.5.0" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-25.5.0.tgz#46352e00533c024c90c2bc2ad9f2959f7f114185" - integrity sha512-9y2+uGnESw/oyOI3eww9yaxdZyHq7XvprfP/eeoCsjqKYts2yRlsHS/SgjPDV8FyMfn2nbMy8YzUk6nyvdLOpQ== +"@jest/fake-timers@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-26.6.2.tgz#459c329bcf70cee4af4d7e3f3e67848123535aad" + integrity sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA== dependencies: - "@jest/types" "^25.5.0" - jest-message-util "^25.5.0" - jest-mock "^25.5.0" - jest-util "^25.5.0" - lolex "^5.0.0" + "@jest/types" "^26.6.2" + "@sinonjs/fake-timers" "^6.0.1" + "@types/node" "*" + jest-message-util "^26.6.2" + jest-mock "^26.6.2" + jest-util "^26.6.2" -"@jest/globals@^25.5.2": - version "25.5.2" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-25.5.2.tgz#5e45e9de8d228716af3257eeb3991cc2e162ca88" - integrity sha512-AgAS/Ny7Q2RCIj5kZ+0MuKM1wbF0WMLxbCVl/GOMoCNbODRdJ541IxJ98xnZdVSZXivKpJlNPIWa3QmY0l4CXA== +"@jest/globals@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-26.6.2.tgz#5b613b78a1aa2655ae908eba638cc96a20df720a" + integrity sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA== dependencies: - "@jest/environment" "^25.5.0" - "@jest/types" "^25.5.0" - expect "^25.5.0" + "@jest/environment" "^26.6.2" + "@jest/types" "^26.6.2" + expect "^26.6.2" -"@jest/reporters@^25.5.1": - version "25.5.1" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-25.5.1.tgz#cb686bcc680f664c2dbaf7ed873e93aa6811538b" - integrity sha512-3jbd8pPDTuhYJ7vqiHXbSwTJQNavczPs+f1kRprRDxETeE3u6srJ+f0NPuwvOmk+lmunZzPkYWIFZDLHQPkviw== +"@jest/reporters@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-26.6.2.tgz#1f518b99637a5f18307bd3ecf9275f6882a667f6" + integrity sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw== dependencies: "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^25.5.0" - "@jest/test-result" "^25.5.0" - "@jest/transform" "^25.5.1" - "@jest/types" "^25.5.0" - chalk "^3.0.0" + "@jest/console" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/transform" "^26.6.2" + "@jest/types" "^26.6.2" + chalk "^4.0.0" collect-v8-coverage "^1.0.0" exit "^0.1.2" glob "^7.1.2" graceful-fs "^4.2.4" istanbul-lib-coverage "^3.0.0" - istanbul-lib-instrument "^4.0.0" + istanbul-lib-instrument "^4.0.3" istanbul-lib-report "^3.0.0" istanbul-lib-source-maps "^4.0.0" istanbul-reports "^3.0.2" - jest-haste-map "^25.5.1" - jest-resolve "^25.5.1" - jest-util "^25.5.0" - jest-worker "^25.5.0" + jest-haste-map "^26.6.2" + jest-resolve "^26.6.2" + jest-util "^26.6.2" + jest-worker "^26.6.2" slash "^3.0.0" source-map "^0.6.0" - string-length "^3.1.0" + string-length "^4.0.1" terminal-link "^2.0.0" - v8-to-istanbul "^4.1.3" + v8-to-istanbul "^7.0.0" optionalDependencies: - node-notifier "^6.0.0" + node-notifier "^8.0.0" -"@jest/source-map@^25.5.0": - version "25.5.0" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-25.5.0.tgz#df5c20d6050aa292c2c6d3f0d2c7606af315bd1b" - integrity sha512-eIGx0xN12yVpMcPaVpjXPnn3N30QGJCJQSkEDUt9x1fI1Gdvb07Ml6K5iN2hG7NmMP6FDmtPEssE3z6doOYUwQ== +"@jest/source-map@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-26.6.2.tgz#29af5e1e2e324cafccc936f218309f54ab69d535" + integrity sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA== dependencies: callsites "^3.0.0" graceful-fs "^4.2.4" source-map "^0.6.0" -"@jest/test-result@^25.5.0": - version "25.5.0" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-25.5.0.tgz#139a043230cdeffe9ba2d8341b27f2efc77ce87c" - integrity sha512-oV+hPJgXN7IQf/fHWkcS99y0smKLU2czLBJ9WA0jHITLst58HpQMtzSYxzaBvYc6U5U6jfoMthqsUlUlbRXs0A== +"@jest/test-result@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-26.6.2.tgz#55da58b62df134576cc95476efa5f7949e3f5f18" + integrity sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ== dependencies: - "@jest/console" "^25.5.0" - "@jest/types" "^25.5.0" + "@jest/console" "^26.6.2" + "@jest/types" "^26.6.2" "@types/istanbul-lib-coverage" "^2.0.0" collect-v8-coverage "^1.0.0" -"@jest/test-sequencer@^25.5.4": - version "25.5.4" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-25.5.4.tgz#9b4e685b36954c38d0f052e596d28161bdc8b737" - integrity sha512-pTJGEkSeg1EkCO2YWq6hbFvKNXk8ejqlxiOg1jBNLnWrgXOkdY6UmqZpwGFXNnRt9B8nO1uWMzLLZ4eCmhkPNA== +"@jest/test-sequencer@^26.6.3": + version "26.6.3" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz#98e8a45100863886d074205e8ffdc5a7eb582b17" + integrity sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw== dependencies: - "@jest/test-result" "^25.5.0" + "@jest/test-result" "^26.6.2" graceful-fs "^4.2.4" - jest-haste-map "^25.5.1" - jest-runner "^25.5.4" - jest-runtime "^25.5.4" + jest-haste-map "^26.6.2" + jest-runner "^26.6.3" + jest-runtime "^26.6.3" -"@jest/transform@^25.5.1": - version "25.5.1" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-25.5.1.tgz#0469ddc17699dd2bf985db55fa0fb9309f5c2db3" - integrity sha512-Y8CEoVwXb4QwA6Y/9uDkn0Xfz0finGkieuV0xkdF9UtZGJeLukD5nLkaVrVsODB1ojRWlaoD0AJZpVHCSnJEvg== +"@jest/transform@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-26.6.2.tgz#5ac57c5fa1ad17b2aae83e73e45813894dcf2e4b" + integrity sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA== dependencies: "@babel/core" "^7.1.0" - "@jest/types" "^25.5.0" + "@jest/types" "^26.6.2" babel-plugin-istanbul "^6.0.0" - chalk "^3.0.0" + chalk "^4.0.0" convert-source-map "^1.4.0" fast-json-stable-stringify "^2.0.0" graceful-fs "^4.2.4" - jest-haste-map "^25.5.1" - jest-regex-util "^25.2.6" - jest-util "^25.5.0" + jest-haste-map "^26.6.2" + jest-regex-util "^26.0.0" + jest-util "^26.6.2" micromatch "^4.0.2" pirates "^4.0.1" - realpath-native "^2.0.0" slash "^3.0.0" source-map "^0.6.1" write-file-atomic "^3.0.0" -"@jest/types@^25.5.0": - version "25.5.0" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-25.5.0.tgz#4d6a4793f7b9599fc3680877b856a97dbccf2a9d" - integrity sha512-OXD0RgQ86Tu3MazKo8bnrkDRaDXXMGUqd+kTtLtK1Zb7CRzQcaSRPPPV37SvYTdevXEBVxe0HXylEjs8ibkmCw== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^1.1.1" - "@types/yargs" "^15.0.0" - chalk "^3.0.0" - -"@jest/types@^26.3.0", "@jest/types@^26.6.2": +"@jest/types@^26.6.2": version "26.6.2" resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e" integrity sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ== @@ -1099,69 +523,191 @@ "@types/yargs" "^15.0.0" chalk "^4.0.0" -"@rollup/plugin-babel@^5.1.0": - version "5.2.1" - resolved "https://registry.yarnpkg.com/@rollup/plugin-babel/-/plugin-babel-5.2.1.tgz#20fc8f8864dc0eaa1c5578408459606808f72924" - integrity sha512-Jd7oqFR2dzZJ3NWANDyBjwTtX/lYbZpVcmkHrfQcpvawHs9E4c0nYk5U2mfZ6I/DZcIvy506KZJi54XK/jxH7A== - dependencies: - "@babel/helper-module-imports" "^7.10.4" - "@rollup/pluginutils" "^3.1.0" - -"@rollup/plugin-commonjs@^11.0.0": - version "11.1.0" - resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-11.1.0.tgz#60636c7a722f54b41e419e1709df05c7234557ef" - integrity sha512-Ycr12N3ZPN96Fw2STurD21jMqzKwL9QuFhms3SD7KKRK7oaXUsBU9Zt0jL/rOPHiPYisI21/rXGO3jr9BnLHUA== - dependencies: - "@rollup/pluginutils" "^3.0.8" - commondir "^1.0.1" - estree-walker "^1.0.1" - glob "^7.1.2" - is-reference "^1.1.2" - magic-string "^0.25.2" - resolve "^1.11.0" - -"@rollup/plugin-json@^4.0.0": - version "4.1.0" - resolved "https://registry.yarnpkg.com/@rollup/plugin-json/-/plugin-json-4.1.0.tgz#54e09867ae6963c593844d8bd7a9c718294496f3" - integrity sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw== +"@jest/types@^27.4.2": + version "27.4.2" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.4.2.tgz#96536ebd34da6392c2b7c7737d693885b5dd44a5" + integrity sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg== dependencies: - "@rollup/pluginutils" "^3.0.8" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^16.0.0" + chalk "^4.0.0" -"@rollup/plugin-node-resolve@^9.0.0": - version "9.0.0" - resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-9.0.0.tgz#39bd0034ce9126b39c1699695f440b4b7d2b62e6" - integrity sha512-gPz+utFHLRrd41WMP13Jq5mqqzHL3OXrfj3/MkSyB6UBIcuNt9j60GCbarzMzdf1VHFpOxfQh/ez7wyadLMqkg== - dependencies: - "@rollup/pluginutils" "^3.1.0" - "@types/resolve" "1.17.1" - builtin-modules "^3.1.0" - deepmerge "^4.2.2" - is-module "^1.0.0" - resolve "^1.17.0" +"@next/env@12.0.8": + version "12.0.8" + resolved "https://registry.yarnpkg.com/@next/env/-/env-12.0.8.tgz#a32ca0a97d464307f2e6ff106ce09b19aac108cf" + integrity sha512-Wa0gOeioB9PHap9wtZDZEhgOSE3/+qE/UALWjJHuNvH4J3oE+13EjVOiEsr1JcPCXUN8ESQE+phDKlo6qJ8P9g== + +"@next/react-refresh-utils@12.0.8": + version "12.0.8" + resolved "https://registry.yarnpkg.com/@next/react-refresh-utils/-/react-refresh-utils-12.0.8.tgz#481760a95ef442abd091663db6582d4dc1b31f06" + integrity sha512-Bq4T/aOOFQUkCF9b8k9x+HpjOevu65ZPxsYJOpgEtBuJyvb+sZREtDDLKb/RtjUeLMrWrsGD0aLteyFFtiS8Og== + +"@next/swc-android-arm64@12.0.8": + version "12.0.8" + resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-12.0.8.tgz#f8dc9663da367a75982730cac058339fb310d79a" + integrity sha512-BiXMcOZNnXSIXv+FQvbRgbMb+iYayLX/Sb2MwR0wja+eMs46BY1x/ssXDwUBADP1M8YtrGTlSPHZqUiCU94+Mg== + +"@next/swc-darwin-arm64@12.0.8": + version "12.0.8" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.0.8.tgz#d6aced7d0a04815dd1324e7982accb3de6a643e8" + integrity sha512-6EGMmvcIwPpwt0/iqLbXDGx6oKHAXzbowyyVXK8cqmIvhoghRFjqfiNGBs+ar6wEBGt68zhwn/77vE3iQWoFJw== + +"@next/swc-darwin-x64@12.0.8": + version "12.0.8" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-12.0.8.tgz#f4fe58d2ed852538410b15a0c80d78908050c716" + integrity sha512-todxgQOGP/ucz5UH2kKR3XGDdkWmWr0VZAAbzgTbiFm45Ol4ih602k2nNR3xSbza9IqNhxNuUVsMpBgeo19CFQ== + +"@next/swc-linux-arm-gnueabihf@12.0.8": + version "12.0.8" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.0.8.tgz#2c02d824fb46e8c6094d7e758c5d7e965070f574" + integrity sha512-KULmdrfI+DJxBuhEyV47MQllB/WpC3P2xbwhHezxL/LkC2nkz5SbV4k432qpx2ebjIRf9SjdQ5Oz1FjD8Urayw== + +"@next/swc-linux-arm64-gnu@12.0.8": + version "12.0.8" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.0.8.tgz#fc32caf3373b299558ede1d889e8555b9ba10ffb" + integrity sha512-1XO87wgIVPvt5fx5i8CqdhksRdcpqyzCOLW4KrE0f9pUCIT04EbsFiKdmsH9c73aqjNZMnCMXpbV+cn4hN8x1w== + +"@next/swc-linux-arm64-musl@12.0.8": + version "12.0.8" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.0.8.tgz#c2d3d7bc2c34da81412b74bdd6e11d0615ae1886" + integrity sha512-NStRZEy/rkk2G18Yhc/Jzi1Q2Dv+zH176oO8479zlDQ5syRfc6AvRHVV4iNRc8Pai58If83r/nOJkwFgGwkKLw== + +"@next/swc-linux-x64-gnu@12.0.8": + version "12.0.8" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.0.8.tgz#029d84f856801b818e5525ab1406f2446821d48c" + integrity sha512-rHxTGtTEDFsdT9/VjewzxE19S7W1NE+aZpm4TwbT1pSNGK9KQxQGcXjqoHMeB+VZCFknzNEoIU/vydbjZMlAuw== + +"@next/swc-linux-x64-musl@12.0.8": + version "12.0.8" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.0.8.tgz#db572da90ab3bce0bc58595c6b8c2d32ec64a2d3" + integrity sha512-1F4kuFRQE10GSx7LMSvRmjMXFGpxT30g8rZzq9r/p/WKdErA4WB4uxaKEX0P8AINfuN63i4luKdR+LoacgBhYw== + +"@next/swc-win32-arm64-msvc@12.0.8": + version "12.0.8" + resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.0.8.tgz#f33e2e56a96489935f87c6dd28f79a7b7ed3778f" + integrity sha512-QuRe49jqCV61TysGopC1P0HPqFAMZMWe1nbIQLyOkDLkULmZR8N2eYZq7fwqvZE5YwhMmJA/grwWFVBqSEh5Kg== + +"@next/swc-win32-ia32-msvc@12.0.8": + version "12.0.8" + resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.0.8.tgz#0f6c7f3e50fc1a4752aed5c862f53c86ce77e3b8" + integrity sha512-0RV3/julybJr1IlPCowIWrJJZyAl+sOakJEM15y1NOOsbwTQ5eKZZXSi+7e23TN4wmy5HwNvn2dKzgOEVJ+jbA== + +"@next/swc-win32-x64-msvc@12.0.8": + version "12.0.8" + resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.0.8.tgz#eae6d4c94dc8aae8ba177e2de02080339d0d4563" + integrity sha512-tTga6OFfO2JS+Yt5hdryng259c/tzNgSWkdiU2E+RBHiysAIOta57n4PJ8iPahOSqEqjaToPI76wM+o441GaNQ== + +"@popperjs/core@^2.6.0": + version "2.11.2" + resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.2.tgz#830beaec4b4091a9e9398ac50f865ddea52186b9" + integrity sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA== -"@rollup/plugin-replace@^2.2.1": - version "2.3.3" - resolved "https://registry.yarnpkg.com/@rollup/plugin-replace/-/plugin-replace-2.3.3.tgz#cd6bae39444de119f5d905322b91ebd4078562e7" - integrity sha512-XPmVXZ7IlaoWaJLkSCDaa0Y6uVo5XQYHhiMFzOd5qSv5rE+t/UJToPIOE56flKIxBFQI27ONsxb7dqHnwSsjKQ== +"@sinonjs/commons@^1.7.0": + version "1.8.3" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d" + integrity sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ== dependencies: - "@rollup/pluginutils" "^3.0.8" - magic-string "^0.25.5" + type-detect "4.0.8" -"@rollup/pluginutils@^3.0.8", "@rollup/pluginutils@^3.0.9", "@rollup/pluginutils@^3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-3.1.0.tgz#706b4524ee6dc8b103b3c995533e5ad680c02b9b" - integrity sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg== +"@sinonjs/fake-timers@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz#293674fccb3262ac782c7aadfdeca86b10c75c40" + integrity sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA== dependencies: - "@types/estree" "0.0.39" - estree-walker "^1.0.1" - picomatch "^2.2.2" + "@sinonjs/commons" "^1.7.0" -"@sinonjs/commons@^1.7.0": - version "1.8.1" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.1.tgz#e7df00f98a203324f6dc7cc606cad9d4a8ab2217" - integrity sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw== - dependencies: - type-detect "4.0.8" +"@swc/core-android-arm-eabi@1.2.133": + version "1.2.133" + resolved "https://registry.yarnpkg.com/@swc/core-android-arm-eabi/-/core-android-arm-eabi-1.2.133.tgz#dea04365897889c6f827ceb544ea241c90f02709" + integrity sha512-S6gc8Z1zhkDmMRwjeGp5Wf8zE+Vwc5m3weSltUTxbO27r48X6A8R2egM48ci/muPTPA6mOWQTViTFcq/hEgV2w== + +"@swc/core-android-arm64@1.2.133": + version "1.2.133" + resolved "https://registry.yarnpkg.com/@swc/core-android-arm64/-/core-android-arm64-1.2.133.tgz#9467327193885692d6b9204599bcb16863e3ccab" + integrity sha512-rlsJ+UCk6QOUVde2l4yeM32R04KbnOM6a2WBw43f5IA8M8PDlWdRNHFE3jiwCIwBoG6MJ+EJE2PPmjxr3iSWvw== + +"@swc/core-darwin-arm64@1.2.133": + version "1.2.133" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.2.133.tgz#95e6d46a8406c4b09e96eec4a3f0bad270285744" + integrity sha512-COktqzeii453+JCGwgIM8vs4y4bgbIzY2lvSEYQmxZRVMAkqQVviLqG4cjm9tYHrW0o+9zpw+XTgpdPpkg32Yg== + +"@swc/core-darwin-x64@1.2.133": + version "1.2.133" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.2.133.tgz#d40999cb465a160c1226fef42df31c7be1ed4999" + integrity sha512-H5Hk+qWotdgVQOuQZdSMmIo4KUGxJjfVVBBbKe+TG1Vqyo5SQderc9TUZH8UzMP/tlX83Nzin0FHB+Ui9UhYqA== + +"@swc/core-freebsd-x64@1.2.133": + version "1.2.133" + resolved "https://registry.yarnpkg.com/@swc/core-freebsd-x64/-/core-freebsd-x64-1.2.133.tgz#0968766e4ff69509ae347e4fed3accb1f1e97c53" + integrity sha512-eFYkZLyAghY90w7CfwHsQ7/doJ46QSlmMGA9qR9NEuPt9MthM84ZXE6d20BvOid0zeib2o6HdFzfaAkS09/hvA== + +"@swc/core-linux-arm-gnueabihf@1.2.133": + version "1.2.133" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.2.133.tgz#fcbefd1783c8fbde44d965ec0fb051387c3c92a9" + integrity sha512-oB9L0Xs6cfOYUr7Qc8tpPd3IpY3dXIaJZ/OZQqFhIQFzeMZVApaLBeyfX+gwH8d8wgceuPj4HeyZE+IWw2GTJQ== + +"@swc/core-linux-arm64-gnu@1.2.133": + version "1.2.133" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.2.133.tgz#2d2986824aaf1dd58c4b4e173d6186b7e2073d54" + integrity sha512-SF0Yviv+9L1ELsn578/TJd44rIhqbGGAD+AgpyJB8YGoFTAFUTnoAhFYNEPOEfbf/IQyWcyHk3vAZ7a2VPRIFg== + +"@swc/core-linux-arm64-musl@1.2.133": + version "1.2.133" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.2.133.tgz#9daae6e86b9c692aecdaa6109721a5ff00d114ad" + integrity sha512-tZiqwz7dTOxnGMwnYguULKl6gNom6CQWXoUyoliksaZA6+uNALO1/PNh/ctzuDbu2Agj4ltsmoevhZlrzC3geA== + +"@swc/core-linux-x64-gnu@1.2.133": + version "1.2.133" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.2.133.tgz#77439a67f2e39125b2f6c5c62d70accaf5140323" + integrity sha512-xXx+/x9y803chUtOqsETvZjimCEiFNcYobsV4wDzlO/E9njrDhmteGcHOv5C6cGSfP6H8tG+hL1JlqJQm+hPSQ== + +"@swc/core-linux-x64-musl@1.2.133": + version "1.2.133" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.2.133.tgz#f37122c608d9392a3dbda4189e1d68db46f49614" + integrity sha512-LnLY5MnwG/L7U+FC/k5LU4K7h+kz5/fo8DC507BncSZj5LLxT9ohhCxO+iUp7qKGw+UQFgSUgUinh1I8FfV6cQ== + +"@swc/core-win32-arm64-msvc@1.2.133": + version "1.2.133" + resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.2.133.tgz#322ea6234182005a81a2b3e64d3e35273057bd8c" + integrity sha512-Fk4D8v56TOhoP5lRFSoZqWXt8enCdHGbZsSIdz7DSjQyS/VeePXdoZI8vmWUcuy2OSquQ4hpS2o1v3wVSREWiw== + +"@swc/core-win32-ia32-msvc@1.2.133": + version "1.2.133" + resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.2.133.tgz#b9766f17821ce3ae7010577174df2549f92a8a07" + integrity sha512-Sf9UmXSPFr7308OSDfIIU0iLRfzilWlnVfVzUfWLd02Z9t5awBxNYCAZrXxny4FUvTDK9qL+/uY378bFH6tYiw== + +"@swc/core-win32-x64-msvc@1.2.133": + version "1.2.133" + resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.2.133.tgz#5afc09724bac622e6f40ce6cd5e901e1458aad98" + integrity sha512-nXZJihzwUjzzF78ipPp+uUWmLQtbFzuR5eADNk1MsnHgWflKaL5OXNVz5c8+qyTl5/c3/W1b4GSevFOfEuApxw== + +"@swc/core@^1.2.131": + version "1.2.133" + resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.2.133.tgz#2d0654b2135ea822e2933c02e150563165bdefff" + integrity sha512-bXrGSrNK9O6Q5dHSazhAVvcGqxSy6ffAIeGSnweHM2cq0Gsrv0Admrj79ERH0dzsubxy4EnY8A0oHj3pEVmL0g== + optionalDependencies: + "@swc/core-android-arm-eabi" "1.2.133" + "@swc/core-android-arm64" "1.2.133" + "@swc/core-darwin-arm64" "1.2.133" + "@swc/core-darwin-x64" "1.2.133" + "@swc/core-freebsd-x64" "1.2.133" + "@swc/core-linux-arm-gnueabihf" "1.2.133" + "@swc/core-linux-arm64-gnu" "1.2.133" + "@swc/core-linux-arm64-musl" "1.2.133" + "@swc/core-linux-x64-gnu" "1.2.133" + "@swc/core-linux-x64-musl" "1.2.133" + "@swc/core-win32-arm64-msvc" "1.2.133" + "@swc/core-win32-ia32-msvc" "1.2.133" + "@swc/core-win32-x64-msvc" "1.2.133" + +"@swc/jest@^0.2.17": + version "0.2.17" + resolved "https://registry.yarnpkg.com/@swc/jest/-/jest-0.2.17.tgz#0a36083cf5bca39c3c03323cdfc84b61fd670ac2" + integrity sha512-n/g989+O8xxMcTZnP0phDrrgezGZBQBf7cX4QuzEsn07QkWbqmMsfaCxdF0kzajXublXWJ8yk5vRe3VNk1tczA== + dependencies: + "@jest/create-cache-key-function" "^27.4.2" "@testing-library/dom@^7.26.6", "@testing-library/dom@^7.28.1": version "7.31.2" @@ -1200,7 +746,7 @@ "@babel/runtime" "^7.12.5" "@testing-library/dom" "^7.28.1" -"@testing-library/vue@^5.1.0": +"@testing-library/vue@^5.8.2": version "5.8.2" resolved "https://registry.yarnpkg.com/@testing-library/vue/-/vue-5.8.2.tgz#976b2179dc28ceba8dd63b5437edc2749f860252" integrity sha512-evsQjLw3T/c92ZsXflZMzSN72P06VlgUZMIcrRKn5n9ZX7QgQyebB3DgdmPACf6JgNfP8Y3Lm2212FmeMnWlZw== @@ -1209,15 +755,20 @@ "@testing-library/dom" "^7.26.6" "@vue/test-utils" "^1.1.0" +"@tootallnate/once@1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" + integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== + "@types/aria-query@^4.2.0": version "4.2.2" resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-4.2.2.tgz#ed4e0ad92306a704f9fb132a0cfcf77486dbe2bc" integrity sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig== -"@types/babel__core@^7.1.7": - version "7.1.10" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.10.tgz#ca58fc195dd9734e77e57c6f2df565623636ab40" - integrity sha512-x8OM8XzITIMyiwl5Vmo2B1cR1S1Ipkyv4mdlbJjMa1lmuKvKY9FrBbEANIaMlnWn5Rf7uO+rC/VgYabNkE17Hw== +"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.7": + version "7.1.18" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.18.tgz#1a29abcc411a9c05e2094c98f9a1b7da6cdf49f8" + integrity sha512-S7unDjm/C7z2A2R9NzfKCK1I+BAALDtxEmsJBwlB3EzNfb929ykjL++1CK9LO++EIp2fQrC8O+BwjKvz6UeDyQ== dependencies: "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" @@ -1226,59 +777,39 @@ "@types/babel__traverse" "*" "@types/babel__generator@*": - version "7.6.1" - resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.1.tgz#4901767b397e8711aeb99df8d396d7ba7b7f0e04" - integrity sha512-bBKm+2VPJcMRVwNhxKu8W+5/zT7pwNEqeokFOmbvVSqGzFneNxYcEBro9Ac7/N9tlsaPYnZLK8J1LWKkMsLAew== + version "7.6.4" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.4.tgz#1f20ce4c5b1990b37900b63f050182d28c2439b7" + integrity sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg== dependencies: "@babel/types" "^7.0.0" "@types/babel__template@*": - version "7.0.2" - resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.0.2.tgz#4ff63d6b52eddac1de7b975a5223ed32ecea9307" - integrity sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg== + version "7.4.1" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" + integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== dependencies: "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" -"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": - version "7.0.14" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.0.14.tgz#e99da8c075d4fb098c774ba65dabf7dc9954bd13" - integrity sha512-8w9szzKs14ZtBVuP6Wn7nMLRJ0D6dfB0VEBEyRgxrZ/Ln49aNMykrghM2FaNn4FJRzNppCSa0Rv9pBRM5Xc3wg== +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.4", "@types/babel__traverse@^7.0.6": + version "7.14.2" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.14.2.tgz#ffcd470bbb3f8bf30481678fb5502278ca833a43" + integrity sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA== dependencies: "@babel/types" "^7.3.0" -"@types/eslint-visitor-keys@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" - integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag== - -"@types/estree@*": - version "0.0.45" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.45.tgz#e9387572998e5ecdac221950dab3e8c3b16af884" - integrity sha512-jnqIUKDUqJbDIUxm0Uj7bnlMnRm1T/eZ9N+AVMqhPgzrba2GhGG5o/jCTwmdPK709nEZsGoMzXEDUjcXHa3W0g== - -"@types/estree@0.0.39": - version "0.0.39" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" - integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== - "@types/graceful-fs@^4.1.2": - version "4.1.3" - resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.3.tgz#039af35fe26bec35003e8d86d2ee9c586354348f" - integrity sha512-AiHRaEB50LQg0pZmm659vNBb9f4SJ0qrAnteuzhSeAUcJKxoYgEnprg/83kppCnc2zvtCKbdZry1a5pVY3lOTQ== + version "4.1.5" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" + integrity sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw== dependencies: "@types/node" "*" -"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": version "2.0.4" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== -"@types/istanbul-lib-coverage@^2.0.1": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762" - integrity sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw== - "@types/istanbul-lib-report@*": version "3.0.0" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" @@ -1286,14 +817,6 @@ dependencies: "@types/istanbul-lib-coverage" "*" -"@types/istanbul-reports@^1.1.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz#e875cc689e47bce549ec81f3df5e6f6f11cfaeb2" - integrity sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw== - dependencies: - "@types/istanbul-lib-coverage" "*" - "@types/istanbul-lib-report" "*" - "@types/istanbul-reports@^3.0.0": version "3.0.1" resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" @@ -1309,24 +832,6 @@ jest-diff "^27.0.0" pretty-format "^27.0.0" -"@types/jest@^25.2.1": - version "25.2.3" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-25.2.3.tgz#33d27e4c4716caae4eced355097a47ad363fdcaf" - integrity sha512-JXc1nK/tXHiDhV55dvfzqtmP4S3sy3T3ouV2tkViZgxY/zeUkcpQcQPGRlgF4KmWzWW5oiWYSZwtCB+2RsE4Fw== - dependencies: - jest-diff "^25.2.1" - pretty-format "^25.2.1" - -"@types/json-schema@^7.0.3": - version "7.0.6" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0" - integrity sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw== - -"@types/json5@^0.0.29": - version "0.0.29" - resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" - integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= - "@types/node@*": version "17.0.10" resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.10.tgz#616f16e9d3a2a3d618136b1be244315d95bd7cab" @@ -1338,24 +843,19 @@ integrity sha512-j11XSuRuAlft6vLDEX4RvhqC0KxNxx6QIyMXNb0vHHSNPXTPeiy3algESWmOOIzEtiEL0qiowPU3ewW9hHVa7Q== "@types/normalize-package-data@^2.4.0": - version "2.4.0" - resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" - integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA== + version "2.4.1" + resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" + integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw== "@types/parse-json@^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== -"@types/prettier@^1.19.0": - version "1.19.1" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-1.19.1.tgz#33509849f8e679e4add158959fdb086440e9553f" - integrity sha512-5qOlnZscTn4xxM5MeGXAMOsIOIKIbh9e85zJWfBRVPlRMEVawzoPhINYbRGkBZCI8LxvBe7tJCdWiarA99OZfQ== - "@types/prettier@^2.0.0": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.1.1.tgz#be148756d5480a84cde100324c03a86ae5739fb5" - integrity sha512-2zs+O+UkDsJ1Vcp667pd3f8xearMdopz/z54i99wtRDI5KLmngk7vlrYZD0ZjKHaROR03EznlBbVY9PfAEyJIQ== + version "2.4.3" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.4.3.tgz#a3c65525b91fca7da00ab1a3ac2b5a2a4afbffbf" + integrity sha512-QzSuZMBuG5u8HqYz01qtMdg/Jfctlnvj1z/lYnIDXs/golxw0fxtRAHd9KrzjR7Yxz1qVeI00o0kiO3PmVdJ9w== "@types/prop-types@*": version "15.7.4" @@ -1378,22 +878,15 @@ "@types/scheduler" "*" csstype "^3.0.2" -"@types/resolve@1.17.1": - version "1.17.1" - resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6" - integrity sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw== - dependencies: - "@types/node" "*" - "@types/scheduler@*": version "0.16.2" resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== -"@types/stack-utils@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e" - integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw== +"@types/stack-utils@^2.0.0": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" + integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== "@types/testing-library__jest-dom@^5.9.1": version "5.14.2" @@ -1414,96 +907,202 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@^2.12.0": - version "2.34.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.34.0.tgz#6f8ce8a46c7dea4a6f1d171d2bb8fbae6dac2be9" - integrity sha512-4zY3Z88rEE99+CNvTbXSyovv2z9PNOVffTWD2W8QF5s2prBQtwN2zadqERcrHpcR7O/+KMI3fcTAmUUhK/iQcQ== - dependencies: - "@typescript-eslint/experimental-utils" "2.34.0" - functional-red-black-tree "^1.0.1" - regexpp "^3.0.0" - tsutils "^3.17.1" - -"@typescript-eslint/experimental-utils@2.34.0": - version "2.34.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.34.0.tgz#d3524b644cdb40eebceca67f8cf3e4cc9c8f980f" - integrity sha512-eS6FTkq+wuMJ+sgtuNTtcqavWXqsflWcfBnlYhg/nS4aZ1leewkXGbvBhaapn1q6qf4M71bsR1tez5JTRMuqwA== - dependencies: - "@types/json-schema" "^7.0.3" - "@typescript-eslint/typescript-estree" "2.34.0" - eslint-scope "^5.0.0" - eslint-utils "^2.0.0" - -"@typescript-eslint/parser@^2.12.0": - version "2.34.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.34.0.tgz#50252630ca319685420e9a39ca05fe185a256bc8" - integrity sha512-03ilO0ucSD0EPTw2X4PntSIRFtDPWjrVq7C3/Z3VQHRC7+13YB55rcJI3Jt+YgeHbjUdJPcPa7b23rXCBokuyA== - dependencies: - "@types/eslint-visitor-keys" "^1.0.0" - "@typescript-eslint/experimental-utils" "2.34.0" - "@typescript-eslint/typescript-estree" "2.34.0" - eslint-visitor-keys "^1.1.0" - -"@typescript-eslint/typescript-estree@2.34.0": - version "2.34.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz#14aeb6353b39ef0732cc7f1b8285294937cf37d5" - integrity sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg== +"@types/yargs@^16.0.0": + version "16.0.4" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.4.tgz#26aad98dd2c2a38e421086ea9ad42b9e51642977" + integrity sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw== dependencies: - debug "^4.1.1" - eslint-visitor-keys "^1.1.0" - glob "^7.1.6" - is-glob "^4.0.1" - lodash "^4.17.15" - semver "^7.3.2" - tsutils "^3.17.1" + "@types/yargs-parser" "*" -"@vue/compiler-core@3.0.7": - version "3.0.7" - resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.0.7.tgz#421782a4c67cc3f2b7c30457ef446d74f8524f74" - integrity sha512-JFohgBXoyUc3mdeI2WxlhjQZ5fakfemJkZHX8Gu/nFbEg3+lKVUZmNKWmmnp9aOzJQZKoj77LjmFxiP+P+7lMQ== +"@vitejs/plugin-vue@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue/-/plugin-vue-2.0.1.tgz#db0e5eacf96358e04cc501c9008079b25a70a4ac" + integrity sha512-wtdMnGVvys9K8tg+DxowU1ytTrdVveXr3LzdhaKakysgGXyrsfaeds2cDywtvujEASjWOwWL/OgWM+qoeM8Plg== + +"@vue/compiler-core@3.2.28": + version "3.2.28" + resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.2.28.tgz#7f6aa4b167f0ae0413f3c36e507c898db06e8fe8" + integrity sha512-mQpfEjmHVxmWKaup0HL6tLMv2HqjjJu7XT4/q0IoUXYXC4xKG8lIVn5YChJqxBTLPuQjzas7u7i9L4PAWJZRtA== dependencies: - "@babel/parser" "^7.12.0" - "@babel/types" "^7.12.0" - "@vue/shared" "3.0.7" - estree-walker "^2.0.1" + "@babel/parser" "^7.16.4" + "@vue/shared" "3.2.28" + estree-walker "^2.0.2" source-map "^0.6.1" -"@vue/compiler-dom@3.0.7": - version "3.0.7" - resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.0.7.tgz#54d2e12fb9a7aff53abd19dac2c2679533f0c919" - integrity sha512-VnIH9EbWQm/Tkcp+8dCaNVsVvhm/vxCrIKWRkXY9215hTqOqQOvejT8IMjd2kc++nIsYMsdQk6H9qqBvoLe/Cw== +"@vue/compiler-core@3.2.29": + version "3.2.29" + resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.2.29.tgz#b06097ab8ff0493177c68c5ea5b63d379a061097" + integrity sha512-RePZ/J4Ub3sb7atQw6V6Rez+/5LCRHGFlSetT3N4VMrejqJnNPXKUt5AVm/9F5MJriy2w/VudEIvgscCfCWqxw== dependencies: - "@vue/compiler-core" "3.0.7" - "@vue/shared" "3.0.7" + "@babel/parser" "^7.16.4" + "@vue/shared" "3.2.29" + estree-walker "^2.0.2" + source-map "^0.6.1" + +"@vue/compiler-dom@3.2.28": + version "3.2.28" + resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.2.28.tgz#cc32a987fee50673f25430df35ea943f252c23e6" + integrity sha512-KA4yXceLteKC7VykvPnViUixemQw3A+oii+deSbZJOQKQKVh1HLosI10qxa8ImPCyun41+wG3uGR+tW7eu1W6Q== + dependencies: + "@vue/compiler-core" "3.2.28" + "@vue/shared" "3.2.28" + +"@vue/compiler-dom@3.2.29": + version "3.2.29" + resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.2.29.tgz#ad0ead405bd2f2754161335aad9758aa12430715" + integrity sha512-y26vK5khdNS9L3ckvkqJk/78qXwWb75Ci8iYLb67AkJuIgyKhIOcR1E8RIt4mswlVCIeI9gQ+fmtdhaiTAtrBQ== + dependencies: + "@vue/compiler-core" "3.2.29" + "@vue/shared" "3.2.29" + +"@vue/compiler-sfc@3.2.28": + version "3.2.28" + resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.2.28.tgz#0a576c09abc72d6a76b153133de6fd7599c182c3" + integrity sha512-zB0WznfEBb4CbGBHzhboHDKVO5nxbkbxxFo9iVlxObP7a9/qvA5kkZEuT7nXP52f3b3qEfmVTjIT23Lo1ndZdQ== + dependencies: + "@babel/parser" "^7.16.4" + "@vue/compiler-core" "3.2.28" + "@vue/compiler-dom" "3.2.28" + "@vue/compiler-ssr" "3.2.28" + "@vue/reactivity-transform" "3.2.28" + "@vue/shared" "3.2.28" + estree-walker "^2.0.2" + magic-string "^0.25.7" + postcss "^8.1.10" + source-map "^0.6.1" + +"@vue/compiler-sfc@3.2.29": + version "3.2.29" + resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.2.29.tgz#f76d556cd5fca6a55a3ea84c88db1a2a53a36ead" + integrity sha512-X9+0dwsag2u6hSOP/XsMYqFti/edvYvxamgBgCcbSYuXx1xLZN+dS/GvQKM4AgGS4djqo0jQvWfIXdfZ2ET68g== + dependencies: + "@babel/parser" "^7.16.4" + "@vue/compiler-core" "3.2.29" + "@vue/compiler-dom" "3.2.29" + "@vue/compiler-ssr" "3.2.29" + "@vue/reactivity-transform" "3.2.29" + "@vue/shared" "3.2.29" + estree-walker "^2.0.2" + magic-string "^0.25.7" + postcss "^8.1.10" + source-map "^0.6.1" + +"@vue/compiler-ssr@3.2.28": + version "3.2.28" + resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.2.28.tgz#411e8b3bdc3183b2acd35e6551734b34366d64e5" + integrity sha512-z8rck1PDTu20iLyip9lAvIhaO40DUJrw3Zv0mS4Apfh3PlfWpF5dhsO5g0dgt213wgYsQIYVIlU9cfrYapqRgg== + dependencies: + "@vue/compiler-dom" "3.2.28" + "@vue/shared" "3.2.28" + +"@vue/compiler-ssr@3.2.29": + version "3.2.29" + resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.2.29.tgz#37b15b32dcd2f6b410bb61fca3f37b1a92b7eb1e" + integrity sha512-LrvQwXlx66uWsB9/VydaaqEpae9xtmlUkeSKF6aPDbzx8M1h7ukxaPjNCAXuFd3fUHblcri8k42lfimHfzMICA== + dependencies: + "@vue/compiler-dom" "3.2.29" + "@vue/shared" "3.2.29" + +"@vue/devtools-api@^6.0.0-beta.18": + version "6.0.0-beta.21.1" + resolved "https://registry.yarnpkg.com/@vue/devtools-api/-/devtools-api-6.0.0-beta.21.1.tgz#f1410f53c42aa67fa3b01ca7bdba891f69d7bc97" + integrity sha512-FqC4s3pm35qGVeXRGOjTsRzlkJjrBLriDS9YXbflHLsfA9FrcKzIyWnLXoNm+/7930E8rRakXuAc2QkC50swAw== + +"@vue/reactivity-transform@3.2.28": + version "3.2.28" + resolved "https://registry.yarnpkg.com/@vue/reactivity-transform/-/reactivity-transform-3.2.28.tgz#e0abf86694f4d182f974fbac934fc3e23e0a6d9b" + integrity sha512-zE8idNkOPnBDd2tKSIk84hOQZ+jXKvSy5FoIIVlcNEJHnCFnQ3maqeSJ9KoB2Rf6EXUhFTiTDNRlYlXmT2uHbQ== + dependencies: + "@babel/parser" "^7.16.4" + "@vue/compiler-core" "3.2.28" + "@vue/shared" "3.2.28" + estree-walker "^2.0.2" + magic-string "^0.25.7" + +"@vue/reactivity-transform@3.2.29": + version "3.2.29" + resolved "https://registry.yarnpkg.com/@vue/reactivity-transform/-/reactivity-transform-3.2.29.tgz#a08d606e10016b7cf588d1a43dae4db2953f9354" + integrity sha512-YF6HdOuhdOw6KyRm59+3rML8USb9o8mYM1q+SH0G41K3/q/G7uhPnHGKvspzceD7h9J3VR1waOQ93CUZj7J7OA== + dependencies: + "@babel/parser" "^7.16.4" + "@vue/compiler-core" "3.2.29" + "@vue/shared" "3.2.29" + estree-walker "^2.0.2" + magic-string "^0.25.7" + +"@vue/reactivity@3.2.28": + version "3.2.28" + resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.2.28.tgz#1c3c7f434372edd867f937151897fca7efc4be18" + integrity sha512-WamM5LGv7JIarW+EYAzYFqYonZXjTnOjNW0sBO93jRE9I1ReAwfH8NvQXkPA3JZ3fuF6SGDdG8Y9/+dKjd/1Gw== + dependencies: + "@vue/shared" "3.2.28" + +"@vue/reactivity@3.2.29": + version "3.2.29" + resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.2.29.tgz#afdc9c111d4139b14600be17ad80267212af6052" + integrity sha512-Ryhb6Gy62YolKXH1gv42pEqwx7zs3n8gacRVZICSgjQz8Qr8QeCcFygBKYfJm3o1SccR7U+bVBQDWZGOyG1k4g== + dependencies: + "@vue/shared" "3.2.29" + +"@vue/runtime-core@3.2.28": + version "3.2.28" + resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.2.28.tgz#69d8eede42957a1660b964004aa002982ae36a41" + integrity sha512-sVbBMFUt42JatTlXbdH6tVcLPw1eEOrrVQWI+j6/nJVzR852RURaT6DhdR0azdYscxq4xmmBctE0VQmlibBOFw== + dependencies: + "@vue/reactivity" "3.2.28" + "@vue/shared" "3.2.28" + +"@vue/runtime-core@3.2.29": + version "3.2.29" + resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.2.29.tgz#fb8577b2fcf52e8d967bd91cdf49ab9fb91f9417" + integrity sha512-VMvQuLdzoTGmCwIKTKVwKmIL0qcODIqe74JtK1pVr5lnaE0l25hopodmPag3RcnIcIXe+Ye3B2olRCn7fTCgig== + dependencies: + "@vue/reactivity" "3.2.29" + "@vue/shared" "3.2.29" + +"@vue/runtime-dom@3.2.28": + version "3.2.28" + resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.2.28.tgz#b5a0cf38daed5534edbc95790f4eeac97dff2003" + integrity sha512-Jg7cxZanEXXGu1QnZILFLnDrM+MIFN8VAullmMZiJEZziHvhygRMpi0ahNy/8OqGwtTze1JNhLdHRBO+q2hbmg== + dependencies: + "@vue/runtime-core" "3.2.28" + "@vue/shared" "3.2.28" + csstype "^2.6.8" + +"@vue/runtime-dom@3.2.29": + version "3.2.29" + resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.2.29.tgz#35e9a2bf04ef80b86ac2ca0e7b2ceaccf1e18f01" + integrity sha512-YJgLQLwr+SQyORzTsBQLL5TT/5UiV83tEotqjL7F9aFDIQdFBTCwpkCFvX9jqwHoyi9sJqM9XtTrMcc8z/OjPA== + dependencies: + "@vue/runtime-core" "3.2.29" + "@vue/shared" "3.2.29" + csstype "^2.6.8" -"@vue/reactivity@3.0.7": - version "3.0.7" - resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.0.7.tgz#e6ccc7bef7fc10b0972e4d974bad71679d3b26ad" - integrity sha512-FotWcNNaKhqpFZrdgsUOZ1enlJ5lhTt01CNTtLSyK7jYFgZBTuw8vKsEutZKDYZ1XKotOfoeO8N3pZQqmM6Etw== +"@vue/server-renderer@3.2.28": + version "3.2.28" + resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.2.28.tgz#235944dc4d969fadd387f62acc2eb8b8d50008a2" + integrity sha512-S+MhurgkPabRvhdDl8R6efKBmniJqBbbWIYTXADaJIKFLFLQCW4gcYUTbxuebzk6j3z485vpekhrHHymTF52Pg== dependencies: - "@vue/shared" "3.0.7" + "@vue/compiler-ssr" "3.2.28" + "@vue/shared" "3.2.28" -"@vue/runtime-core@3.0.7": - version "3.0.7" - resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.0.7.tgz#d44c0b0a57d7e392912a87362a4430ccf446ecea" - integrity sha512-DBAZAwVvdmMXuyd6/9qqj/kYr/GaLTmn1L2/QLxLwP+UfhIboiTSBc/tUUb8MRk7Bb98GzNeAWkkT6AfooS3dQ== +"@vue/server-renderer@3.2.29": + version "3.2.29" + resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.2.29.tgz#ea6afa361b9c781a868c8da18c761f9b7bc89102" + integrity sha512-lpiYx7ciV7rWfJ0tPkoSOlLmwqBZ9FTmQm33S+T4g0j1fO/LmhJ9b9Ctl1o5xvIFVDk9QkSUWANZn7H2pXuxVw== dependencies: - "@vue/reactivity" "3.0.7" - "@vue/shared" "3.0.7" + "@vue/compiler-ssr" "3.2.29" + "@vue/shared" "3.2.29" -"@vue/runtime-dom@3.0.7": - version "3.0.7" - resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.0.7.tgz#b70668d729020bc4ad608c20367223f259576ba6" - integrity sha512-Oij4ruOtnpQpCj+/Q3JPzgpTJ1Q7+N67pA53A8KVITEtxfvKL46NN6dhAZ5NGqwX6RWZpYqWQNewITeF0pHr8g== - dependencies: - "@vue/runtime-core" "3.0.7" - "@vue/shared" "3.0.7" - csstype "^2.6.8" +"@vue/shared@3.2.28": + version "3.2.28" + resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.2.28.tgz#5b0b1840432031d0ea1adff633b356a503e87048" + integrity sha512-eMQ8s9j8FpbGHlgUAaj/coaG3Q8YtMsoWL/RIHTsE3Ex7PUTyr7V91vB5HqWB5Sn8m4RXTHGO22/skoTUYvp0A== -"@vue/shared@3.0.7": - version "3.0.7" - resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.0.7.tgz#96d52988efc07444c108c7c6803ba7cc93e40045" - integrity sha512-dn5FyfSc4ky424jH4FntiHno7Ss5yLkqKNmM/NXwANRnlkmqu74pnGetexDFVG5phMk9/FhwovUZCWGxsotVKg== +"@vue/shared@3.2.29": + version "3.2.29" + resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.2.29.tgz#07dac7051117236431d2f737d16932aa38bbb925" + integrity sha512-BjNpU8OK6Z0LVzGUppEk0CMYm/hKDnZfYdjSmPOs0N+TR1cLKJAkDwW8ASZUvaaSLEi6d3hVM7jnWnX+6yWnHw== "@vue/test-utils@^1.1.0": version "1.3.0" @@ -1514,12 +1113,12 @@ lodash "^4.17.15" pretty "^2.0.0" -"@vue/test-utils@^2.0.0-beta.7": +"@vue/test-utils@^2.0.0-rc.18": version "2.0.0-rc.18" resolved "https://registry.yarnpkg.com/@vue/test-utils/-/test-utils-2.0.0-rc.18.tgz#ff22b252424fe72e5462cbb3a8e7405cef11ffb6" integrity sha512-aifolXjVdsogjaLmDoZ0FU8vN+R67aWmg9OuVeED4w5Ij5GFQLrlhM19uhWe/r5xXUL4fXMk3pX5wW6FJP1NcQ== -abab@^2.0.0: +abab@^2.0.3, abab@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q== @@ -1529,33 +1128,35 @@ abbrev@1: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== -acorn-globals@^4.3.2: - version "4.3.4" - resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.3.4.tgz#9fa1926addc11c97308c4e66d7add0d40c3272e7" - integrity sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A== +acorn-globals@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" + integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg== dependencies: - acorn "^6.0.1" - acorn-walk "^6.0.1" + acorn "^7.1.1" + acorn-walk "^7.1.1" -acorn-jsx@^5.2.0: - version "5.3.1" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b" - integrity sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng== +acorn-walk@^7.1.1: + version "7.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" + integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== -acorn-walk@^6.0.1: - version "6.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-6.2.0.tgz#123cb8f3b84c2171f1f7fb252615b1c78a6b1a8c" - integrity sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA== +acorn@^7.1.1: + version "7.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -acorn@^6.0.1: - version "6.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474" - integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA== +acorn@^8.2.4: + version "8.7.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" + integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== -acorn@^7.1.0, acorn@^7.1.1: - version "7.4.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.0.tgz#e1ad486e6c54501634c6c397c5c121daa383607c" - integrity sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w== +agent-base@6: + version "6.0.2" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== + dependencies: + debug "4" aggregate-error@^3.0.0: version "3.1.0" @@ -1565,50 +1166,13 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" -ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3: - version "6.12.5" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.5.tgz#19b0e8bae8f476e5ba666300387775fb1a00a4da" - integrity sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ansi-colors@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" - integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== - -ansi-escapes@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" - integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== - -ansi-escapes@^4.2.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61" - integrity sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA== - dependencies: - type-fest "^0.11.0" - -ansi-escapes@^4.3.0: +ansi-escapes@^4.2.1, ansi-escapes@^4.3.0: version "4.3.2" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== dependencies: type-fest "^0.21.3" -ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= - -ansi-regex@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" - integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== - ansi-regex@^5.0.0, ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" @@ -1619,7 +1183,7 @@ ansi-regex@^6.0.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== -ansi-styles@^3.2.0, ansi-styles@^3.2.1: +ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== @@ -1652,9 +1216,9 @@ anymatch@^2.0.0: normalize-path "^2.1.1" anymatch@^3.0.3: - version "3.1.1" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" - integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg== + version "3.1.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" + integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== dependencies: normalize-path "^3.0.0" picomatch "^2.0.4" @@ -1694,69 +1258,16 @@ arr-union@^3.1.0: resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= -array-equal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" - integrity sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM= - -array-includes@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.1.tgz#cdd67e6852bdf9c1215460786732255ed2459348" - integrity sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0" - is-string "^1.0.5" - array-unique@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= -array.prototype.flat@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz#0de82b426b0318dbfdb940089e38b043d37f6c7b" - integrity sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" - -array.prototype.flatmap@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.2.3.tgz#1c13f84a178566042dd63de4414440db9222e443" - integrity sha512-OOEk+lkePcg+ODXIpvuU9PAryCikCJyo7GlDG1upleEpQRx6mzL9puEBkozQ5iAx20KV0l3DbyQwqciJtqe5Pg== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" - function-bind "^1.1.1" - -asn1@~0.2.3: - version "0.2.4" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" - integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== - dependencies: - safer-buffer "~2.1.0" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= - assign-symbols@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= -ast-types-flow@^0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" - integrity sha1-9wtzXGvKGlycItmCw+Oef+ujva0= - -astral-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" - integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== - astral-regex@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" @@ -1767,129 +1278,50 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= -asyncro@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/asyncro/-/asyncro-3.0.0.tgz#3c7a732e263bc4a42499042f48d7d858e9c0134e" - integrity sha512-nEnWYfrBmA3taTiuiOoZYmgJ/CNrSoQLeLs29SeLcPu60yaw/mHDBHV0iOZ051fTvsTHxpCY+gXibqT9wbQYfg== - -at-least-node@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" - integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== - atob@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= - -aws4@^1.8.0: - version "1.10.1" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.10.1.tgz#e1e82e4f3e999e2cfd61b161280d16a111f86428" - integrity sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA== - -axe-core@^3.5.4: - version "3.5.5" - resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-3.5.5.tgz#84315073b53fa3c0c51676c588d59da09a192227" - integrity sha512-5P0QZ6J5xGikH780pghEdbEKijCTrruK9KxtPZCFWUpef0f6GipO+xEZ5GKCb020mmqgbiNO6TcA55CriL784Q== - -axobject-query@^2.1.2: - version "2.2.0" - resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be" - integrity sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA== - -babel-eslint@^10.0.3: - version "10.1.0" - resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232" - integrity sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg== +babel-jest@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-26.6.3.tgz#d87d25cb0037577a0c89f82e5755c5d293c01056" + integrity sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA== dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/parser" "^7.7.0" - "@babel/traverse" "^7.7.0" - "@babel/types" "^7.7.0" - eslint-visitor-keys "^1.0.0" - resolve "^1.12.0" - -babel-jest@^25.5.1: - version "25.5.1" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-25.5.1.tgz#bc2e6101f849d6f6aec09720ffc7bc5332e62853" - integrity sha512-9dA9+GmMjIzgPnYtkhBg73gOo/RHqPmLruP3BaGL4KEX3Dwz6pI8auSN8G8+iuEG90+GSswyKvslN+JYSaacaQ== - dependencies: - "@jest/transform" "^25.5.1" - "@jest/types" "^25.5.0" + "@jest/transform" "^26.6.2" + "@jest/types" "^26.6.2" "@types/babel__core" "^7.1.7" babel-plugin-istanbul "^6.0.0" - babel-preset-jest "^25.5.0" - chalk "^3.0.0" + babel-preset-jest "^26.6.2" + chalk "^4.0.0" graceful-fs "^4.2.4" slash "^3.0.0" -babel-plugin-annotate-pure-calls@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/babel-plugin-annotate-pure-calls/-/babel-plugin-annotate-pure-calls-0.4.0.tgz#78aa00fd878c4fcde4d49f3da397fcf5defbcce8" - integrity sha512-oi4M/PWUJOU9ZyRGoPTfPMqdyMp06jbJAomd3RcyYuzUtBOddv98BqLm96Lucpi2QFoQHkdGQt0ACvw7VzVEQA== - -babel-plugin-dev-expression@^0.2.1: - version "0.2.2" - resolved "https://registry.yarnpkg.com/babel-plugin-dev-expression/-/babel-plugin-dev-expression-0.2.2.tgz#c18de18a06150f9480edd151acbb01d2e65e999b" - integrity sha512-y32lfBif+c2FIh5dwGfcc/IfX5aw/Bru7Du7W2n17sJE/GJGAsmIk5DPW/8JOoeKpXW5evJfJOvRq5xkiS6vng== - -babel-plugin-dynamic-import-node@^2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" - integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ== - dependencies: - object.assign "^4.1.0" - babel-plugin-istanbul@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz#e159ccdc9af95e0b570c75b4573b7c34d671d765" - integrity sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ== + version "6.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@istanbuljs/load-nyc-config" "^1.0.0" "@istanbuljs/schema" "^0.1.2" - istanbul-lib-instrument "^4.0.0" + istanbul-lib-instrument "^5.0.4" test-exclude "^6.0.0" -babel-plugin-jest-hoist@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-25.5.0.tgz#129c80ba5c7fc75baf3a45b93e2e372d57ca2677" - integrity sha512-u+/W+WAjMlvoocYGTwthAiQSxDcJAyHpQ6oWlHdFZaaN+Rlk8Q7iiwDPg2lN/FyJtAYnKjFxbn7xus4HCFkg5g== +babel-plugin-jest-hoist@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz#8185bd030348d254c6d7dd974355e6a28b21e62d" + integrity sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw== dependencies: "@babel/template" "^7.3.3" "@babel/types" "^7.3.3" + "@types/babel__core" "^7.0.0" "@types/babel__traverse" "^7.0.6" -babel-plugin-macros@^2.6.1: - version "2.8.0" - resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz#0f958a7cc6556b1e65344465d99111a1e5e10138" - integrity sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg== - dependencies: - "@babel/runtime" "^7.7.2" - cosmiconfig "^6.0.0" - resolve "^1.12.0" - -babel-plugin-polyfill-regenerator@^0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.0.4.tgz#588641af9a2cb4e299b1400c47672a4a104d2459" - integrity sha512-+/uCzO9JTYVZVGCpZpVAQkgPGt2zkR0VYiZvJ4aVoCe4ccgpKvNQqcjzAgQzSsjK64Jhc5hvrCR3l0087BevkA== - dependencies: - "@babel/helper-define-polyfill-provider" "^0.0.3" - -babel-plugin-transform-rename-import@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-rename-import/-/babel-plugin-transform-rename-import-2.3.0.tgz#5d9d645f937b0ca5c26a24b2510a06277b6ffd9b" - integrity sha512-dPgJoT57XC0PqSnLgl2FwNvxFrWlspatX2dkk7yjKQj5HHGw071vAcOf+hqW8ClqcBDMvEbm6mevn5yHAD8mlQ== - -babel-preset-current-node-syntax@^0.1.2: - version "0.1.4" - resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-0.1.4.tgz#826f1f8e7245ad534714ba001f84f7e906c3b615" - integrity sha512-5/INNCYhUGqw7VbVjT/hb3ucjgkVHKXY7lX3ZjlN4gm565VyFmJUrJ/h+h16ECVB38R/9SF6aACydpKMLZ/c9w== +babel-preset-current-node-syntax@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" + integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== dependencies: "@babel/plugin-syntax-async-generators" "^7.8.4" "@babel/plugin-syntax-bigint" "^7.8.3" @@ -1902,14 +1334,15 @@ babel-preset-current-node-syntax@^0.1.2: "@babel/plugin-syntax-object-rest-spread" "^7.8.3" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-top-level-await" "^7.8.3" -babel-preset-jest@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-25.5.0.tgz#c1d7f191829487a907764c65307faa0e66590b49" - integrity sha512-8ZczygctQkBU+63DtSOKGh7tFL0CeCuz+1ieud9lJ1WPQ9O6A1a/r+LGn6Y705PA6whHQ3T1XuB/PmpfNYf8Fw== +babel-preset-jest@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz#747872b1171df032252426586881d62d31798fee" + integrity sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ== dependencies: - babel-plugin-jest-hoist "^25.5.0" - babel-preset-current-node-syntax "^0.1.2" + babel-plugin-jest-hoist "^26.6.2" + babel-preset-current-node-syntax "^1.0.0" balanced-match@^1.0.0: version "1.0.2" @@ -1929,12 +1362,10 @@ base@^0.11.1: mixin-deep "^1.2.0" pascalcase "^0.1.1" -bcrypt-pbkdf@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" - integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= - dependencies: - tweetnacl "^0.14.3" +big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== brace-expansion@^1.1.7: version "1.1.11" @@ -1972,29 +1403,16 @@ browser-process-hrtime@^1.0.0: resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== -browser-resolve@^1.11.3: - version "1.11.3" - resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.3.tgz#9b7cbb3d0f510e4cb86bdbd796124d28b5890af6" - integrity sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ== - dependencies: - resolve "1.1.7" - -browserslist@^4.12.0, browserslist@^4.8.5: - version "4.14.3" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.14.3.tgz#381f9e7f13794b2eb17e1761b4f118e8ae665a53" - integrity sha512-GcZPC5+YqyPO4SFnz48/B0YaCwS47Q9iPChRGi6t7HhflKBcINzFrJvRfC+jp30sRMKxF+d4EHGs27Z0XP1NaQ== - dependencies: - caniuse-lite "^1.0.30001131" - electron-to-chromium "^1.3.570" - escalade "^3.1.0" - node-releases "^1.1.61" - -bs-logger@0.x: - version "0.2.6" - resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" - integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== +browserslist@^4.17.5: + version "4.19.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.19.1.tgz#4ac0435b35ab655896c31d53018b6dd5e9e4c9a3" + integrity sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A== dependencies: - fast-json-stable-stringify "2.x" + caniuse-lite "^1.0.30001286" + electron-to-chromium "^1.4.17" + escalade "^3.1.1" + node-releases "^2.0.1" + picocolors "^1.0.0" bser@2.1.1: version "2.1.1" @@ -2003,15 +1421,10 @@ bser@2.1.1: dependencies: node-int64 "^0.4.0" -buffer-from@1.x, buffer-from@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" - integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== - -builtin-modules@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.1.0.tgz#aad97c15131eb76b65b50ef208e7584cd76a7484" - integrity sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw== +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== cache-base@^1.0.1: version "1.0.1" @@ -2028,6 +1441,14 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" +call-bind@^1.0.0, call-bind@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -2039,14 +1460,14 @@ camelcase@^5.0.0, camelcase@^5.3.1: integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== camelcase@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.0.0.tgz#5259f7c30e35e278f1bdc2a4d91230b37cad981e" - integrity sha512-8KMDF1Vz2gzOq54ONPJS65IvTUaB1cHJ2DMM7MbPmLZljDH1qpzzLsWdiN9pHh6qvkRVDTi/07+eNGch/oLU4w== + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -caniuse-lite@^1.0.30001131: - version "1.0.30001191" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001191.tgz" - integrity sha512-xJJqzyd+7GCJXkcoBiQ1GuxEiOBCLQ0aVW9HMekifZsAVGdj5eJ4mFB9fEhSHipq9IOk/QXFJUiIr9lZT+EsGw== +caniuse-lite@^1.0.30001283, caniuse-lite@^1.0.30001286: + version "1.0.30001300" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001300.tgz#11ab6c57d3eb6f964cba950401fd00a146786468" + integrity sha512-cVjiJHWGcNlJi8TZVKNMnvMid3Z3TTdDHmLDzlOdIiZq138Exvo0G+G0wTdVYolxKb4AYwC+38pxodiInVtJSA== capture-exit@^2.0.0: version "2.0.0" @@ -2055,12 +1476,7 @@ capture-exit@^2.0.0: dependencies: rsvp "^4.8.4" -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= - -chalk@^2.0.0, chalk@^2.1.0, chalk@^2.4.1, chalk@^2.4.2: +chalk@^2.0.0, chalk@^2.4.1: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -2085,16 +1501,21 @@ chalk@^4.0.0, chalk@^4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chardet@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" - integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== ci-info@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== +cjs-module-lexer@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz#4186fcca0eae175970aee870b9fe2d6cf8d5655f" + integrity sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw== + class-utils@^0.3.5: version "0.3.6" resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" @@ -2110,13 +1531,6 @@ clean-stack@^2.0.0: resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== -cli-cursor@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" - integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= - dependencies: - restore-cursor "^2.0.0" - cli-cursor@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" @@ -2124,16 +1538,6 @@ cli-cursor@^3.1.0: dependencies: restore-cursor "^3.1.0" -cli-spinners@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-1.3.1.tgz#002c1990912d0d59580c93bd36c056de99e4259a" - integrity sha512-1QL4544moEsDVH9T/l6Cemov/37iv1RtoKf7NJ04A60+4MREXNfx/QvavbH6QoGdsD4N4Mwy49cmaINR/o2mdg== - -cli-spinners@^2.2.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.4.0.tgz#c6256db216b878cfba4720e719cec7cf72685d7f" - integrity sha512-sJAofoarcm76ZGpuooaO0eDy8saEy+YoZBLjC4h8srt4jeBnkYeOgqxgsJQTpyt2LjI5PTfLJHSL+41Yu4fEJA== - cli-truncate@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7" @@ -2150,11 +1554,6 @@ cli-truncate@^3.1.0: slice-ansi "^5.0.0" string-width "^5.0.0" -cli-width@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" - integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== - cliui@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" @@ -2164,11 +1563,6 @@ cliui@^6.0.0: strip-ansi "^6.0.0" wrap-ansi "^6.2.0" -clone@^1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" - integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= - co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -2211,19 +1605,24 @@ color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +colorette@^1.2.2: + version "1.4.0" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.4.0.tgz#5190fbb87276259a86ad700bff2c6d6faa3fca40" + integrity sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g== + colorette@^2.0.16: version "2.0.16" resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.16.tgz#713b9af84fdb000139f04546bd4a93f62a5085da" integrity sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g== -combined-stream@^1.0.6, combined-stream@~1.0.6: +combined-stream@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== dependencies: delayed-stream "~1.0.0" -commander@^2.19.0, commander@^2.20.0: +commander@^2.19.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== @@ -2233,11 +1632,6 @@ commander@^8.3.0: resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== -commondir@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" - integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= - compare-versions@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.6.0.tgz#1a5689913685e5a87637b8d3ffca75514ec41d62" @@ -2270,57 +1664,30 @@ config-chain@^1.1.12: ini "^1.3.4" proto-list "~1.2.1" -confusing-browser-globals@^1.0.9: - version "1.0.9" - resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.9.tgz#72bc13b483c0276801681871d4898516f8f54fdd" - integrity sha512-KbS1Y0jMtyPgIxjO7ZzMAuUpAKMt1SzCL9fsrKsX6b0zJPTaT0SiSPmewwVZg9UAO83HVIlEhZF84LIjZ0lmAw== - -contains-path@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" - integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo= - -convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: +convert-source-map@1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== dependencies: safe-buffer "~5.1.1" +convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" + integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== + dependencies: + safe-buffer "~5.1.1" + copy-descriptor@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= -core-js-compat@^3.6.2: - version "3.6.5" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.6.5.tgz#2a51d9a4e25dfd6e690251aa81f99e3c05481f1c" - integrity sha512-7ItTKOhOZbznhXAQ2g/slGg1PJV5zDO/WdkTwi7UEOJmkvsE32PWvx6mKtDjiMpjnR2CNf6BAD6sSxIlv7ptng== - dependencies: - browserslist "^4.8.5" - semver "7.0.0" - core-js-pure@^3.20.2: version "3.20.3" resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.20.3.tgz#6cc4f36da06c61d95254efc54024fe4797fd5d02" integrity sha512-Q2H6tQ5MtPtcC7f3HxJ48i4Q7T9ybPKgvWyuH7JXIoNa2pm0KuBnycsET/qw1SLLZYfbsbrZQNMeIOClb+6WIA== -core-util-is@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= - -cosmiconfig@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982" - integrity sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg== - dependencies: - "@types/parse-json" "^4.0.0" - import-fresh "^3.1.0" - parse-json "^5.0.0" - path-type "^4.0.0" - yaml "^1.7.2" - cosmiconfig@^7.0.0: version "7.0.1" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d" @@ -2366,7 +1733,7 @@ css@^3.0.0: source-map "^0.6.1" source-map-resolve "^0.6.0" -cssom@^0.4.1: +cssom@^0.4.4: version "0.4.4" resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== @@ -2376,7 +1743,7 @@ cssom@~0.3.6: resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== -cssstyle@^2.0.0: +cssstyle@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== @@ -2393,75 +1760,54 @@ csstype@^3.0.2: resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.10.tgz#2ad3a7bed70f35b965707c092e5f30b327c290e5" integrity sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA== -damerau-levenshtein@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz#143c1641cb3d85c60c32329e26899adea8701791" - integrity sha512-JVrozIeElnj3QzfUIt8tB8YMluBJom4Vw9qTPpjGYQ9fYlB3D/rb6OordUxf3xeFB35LKWs0xqcO5U6ySvBtug== - -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= +data-urls@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" + integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== dependencies: - assert-plus "^1.0.0" + abab "^2.0.3" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.0.0" -data-urls@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-1.1.0.tgz#15ee0582baa5e22bb59c77140da8f9c76963bbfe" - integrity sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ== +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.3: + version "4.3.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" + integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== dependencies: - abab "^2.0.0" - whatwg-mimetype "^2.2.0" - whatwg-url "^7.0.0" + ms "2.1.2" -debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: +debug@^2.2.0, debug@^2.3.3: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: ms "2.0.0" -debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" - integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== - dependencies: - ms "^2.1.1" - -debug@^4.3.3: - version "4.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" - integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== - dependencies: - ms "2.1.2" - decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= +decimal.js@^10.2.1: + version "10.3.1" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783" + integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ== + decode-uri-component@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= deep-is@~0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" - integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== deepmerge@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== -defaults@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" - integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= - dependencies: - clone "^1.0.2" - define-properties@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" @@ -2501,43 +1847,16 @@ detect-newline@^3.0.0: resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== -diff-sequences@^25.2.6: - version "25.2.6" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-25.2.6.tgz#5f467c00edd35352b7bca46d7927d60e687a76dd" - integrity sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg== - -diff-sequences@^26.3.0: - version "26.3.0" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.3.0.tgz#62a59b1b29ab7fd27cef2a33ae52abe73042d0a2" - integrity sha512-5j5vdRcw3CNctePNYN0Wy2e/JbWT6cAYnXv5OuqPhDpyCGc0uLu2TK0zOCJWNB9kOIfYMSpIulRaDgIi4HJ6Ig== +diff-sequences@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1" + integrity sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q== diff-sequences@^27.4.0: version "27.4.0" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.4.0.tgz#d783920ad8d06ec718a060d00196dfef25b132a5" integrity sha512-YqiQzkrsmHMH5uuh8OdQFU9/ZpADnwzml8z0O5HvRNda+5UZsaX/xN+AAxfR2hWq1Y7HZnAzO9J5lJXOuDz2Ww== -doctrine@1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" - integrity sha1-N53Ocw9hZvds76TmcHoVmwLFpvo= - dependencies: - esutils "^2.0.2" - isarray "^1.0.0" - -doctrine@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" - integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== - dependencies: - esutils "^2.0.2" - -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - dom-accessibility-api@^0.5.6: version "0.5.10" resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.10.tgz#caa6d08f60388d0bb4539dd75fe458a9a1d0014c" @@ -2548,26 +1867,18 @@ dom-event-types@^1.0.0: resolved "https://registry.yarnpkg.com/dom-event-types/-/dom-event-types-1.0.0.tgz#5830a0a29e1bf837fe50a70cd80a597232813cae" integrity sha512-2G2Vwi2zXTHBGqXHsJ4+ak/iP0N8Ar+G8a7LiD2oup5o4sQWytwqqrZu/O6hIMV0KMID2PL69OhpshLO0n7UJQ== -domexception@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90" - integrity sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug== +domexception@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" + integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg== dependencies: - webidl-conversions "^4.0.2" + webidl-conversions "^5.0.0" eastasianwidth@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== -ecc-jsbn@~0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" - integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= - dependencies: - jsbn "~0.1.0" - safer-buffer "^2.1.0" - editorconfig@^0.15.3: version "0.15.3" resolved "https://registry.yarnpkg.com/editorconfig/-/editorconfig-0.15.3.tgz#bef84c4e75fb8dcb0ce5cee8efd51c15999befc5" @@ -2578,31 +1889,31 @@ editorconfig@^0.15.3: semver "^5.6.0" sigmund "^1.0.1" -electron-to-chromium@^1.3.570: - version "1.3.570" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.570.tgz#3f5141cc39b4e3892a276b4889980dabf1d29c7f" - integrity sha512-Y6OCoVQgFQBP5py6A/06+yWxUZHDlNr/gNDGatjH8AZqXl8X0tE4LfjLJsXGz/JmWJz8a6K7bR1k+QzZ+k//fg== +electron-to-chromium@^1.4.17: + version "1.4.49" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.49.tgz#5b6a3dc032590beef4be485a4b0b3fe7d0e3dfd7" + integrity sha512-k/0t1TRfonHIp8TJKfjBu2cKj8MqYTiEpOhci+q7CVEE5xnCQnx1pTa+V8b/sdhe4S3PR4p4iceEQWhGrKQORQ== -emoji-regex@^7.0.1: - version "7.0.3" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" - integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== +emittery@^0.7.1: + version "0.7.2" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.7.2.tgz#25595908e13af0f5674ab419396e2fb394cdfa82" + integrity sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ== emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== -emoji-regex@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.0.0.tgz#48a2309cc8a1d2e9d23bc6a67c39b63032e76ea4" - integrity sha512-6p1NII1Vm62wni/VR/cUMauVQoxmLVb9csqQlvLz+hO2gk8U2UYDfXHQSUYIBKmZwAKz867IDqG7B+u0mj+M6w== - emoji-regex@^9.2.2: version "9.2.2" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== +emojis-list@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" + integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= + end-of-stream@^1.1.0: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" @@ -2610,54 +1921,38 @@ end-of-stream@^1.1.0: dependencies: once "^1.4.0" -enquirer@^2.3.4: - version "2.3.6" - resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" - integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== - dependencies: - ansi-colors "^4.1.1" - -error-ex@^1.2.0, error-ex@^1.3.1: +error-ex@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== dependencies: is-arrayish "^0.2.1" -es-abstract@^1.17.0, es-abstract@^1.17.0-next.1, es-abstract@^1.17.5: - version "1.17.6" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.6.tgz#9142071707857b2cacc7b89ecb670316c3e2d52a" - integrity sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw== - dependencies: - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - is-callable "^1.2.0" - is-regex "^1.1.0" - object-inspect "^1.7.0" - object-keys "^1.1.1" - object.assign "^4.1.0" - string.prototype.trimend "^1.0.1" - string.prototype.trimstart "^1.0.1" - -es-abstract@^1.18.0-next.0: - version "1.18.0-next.0" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0-next.0.tgz#b302834927e624d8e5837ed48224291f2c66e6fc" - integrity sha512-elZXTZXKn51hUBdJjSZGYRujuzilgXo8vSPQzjGYXLvSlGiCo8VO8ZGV3kjo9a0WNJJ57hENagwbtlRuHuzkcQ== +es-abstract@^1.19.1: + version "1.19.1" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3" + integrity sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w== dependencies: + call-bind "^1.0.2" es-to-primitive "^1.2.1" function-bind "^1.1.1" + get-intrinsic "^1.1.1" + get-symbol-description "^1.0.0" has "^1.0.3" - has-symbols "^1.0.1" - is-callable "^1.2.0" - is-negative-zero "^2.0.0" - is-regex "^1.1.1" - object-inspect "^1.8.0" + has-symbols "^1.0.2" + internal-slot "^1.0.3" + is-callable "^1.2.4" + is-negative-zero "^2.0.1" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.1" + is-string "^1.0.7" + is-weakref "^1.0.1" + object-inspect "^1.11.0" object-keys "^1.1.1" - object.assign "^4.1.0" - string.prototype.trimend "^1.0.1" - string.prototype.trimstart "^1.0.1" + object.assign "^4.1.2" + string.prototype.trimend "^1.0.4" + string.prototype.trimstart "^1.0.4" + unbox-primitive "^1.0.1" es-to-primitive@^1.2.1: version "1.2.1" @@ -2668,10 +1963,237 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" -escalade@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.0.tgz#e8e2d7c7a8b76f6ee64c2181d6b8151441602d4e" - integrity sha512-mAk+hPSO8fLDkhV7V0dXazH5pDc6MrjBTPyD3VeKzxnVFjH1MIxbCdqGZB9O8+EwWakZs3ZCbDS4IpRt79V1ig== +esbuild-android-arm64@0.13.15: + version "0.13.15" + resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.13.15.tgz#3fc3ff0bab76fe35dd237476b5d2b32bb20a3d44" + integrity sha512-m602nft/XXeO8YQPUDVoHfjyRVPdPgjyyXOxZ44MK/agewFFkPa8tUo6lAzSWh5Ui5PB4KR9UIFTSBKh/RrCmg== + +esbuild-android-arm64@0.14.11: + version "0.14.11" + resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.11.tgz#b8b34e35a5b43880664ac7a3fbc70243d7ed894f" + integrity sha512-6iHjgvMnC/SzDH8TefL+/3lgCjYWwAd1LixYfmz/TBPbDQlxcuSkX0yiQgcJB9k+ibZ54yjVXziIwGdlc+6WNw== + +esbuild-darwin-64@0.13.15: + version "0.13.15" + resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.13.15.tgz#8e9169c16baf444eacec60d09b24d11b255a8e72" + integrity sha512-ihOQRGs2yyp7t5bArCwnvn2Atr6X4axqPpEdCFPVp7iUj4cVSdisgvEKdNR7yH3JDjW6aQDw40iQFoTqejqxvQ== + +esbuild-darwin-64@0.14.11: + version "0.14.11" + resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.11.tgz#ba805de98c0412e50fcd0636451797da157b0625" + integrity sha512-olq84ikh6TiBcrs3FnM4eR5VPPlcJcdW8BnUz/lNoEWYifYQ+Po5DuYV1oz1CTFMw4k6bQIZl8T3yxL+ZT2uvQ== + +esbuild-darwin-arm64@0.13.15: + version "0.13.15" + resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.13.15.tgz#1b07f893b632114f805e188ddfca41b2b778229a" + integrity sha512-i1FZssTVxUqNlJ6cBTj5YQj4imWy3m49RZRnHhLpefFIh0To05ow9DTrXROTE1urGTQCloFUXTX8QfGJy1P8dQ== + +esbuild-darwin-arm64@0.14.11: + version "0.14.11" + resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.11.tgz#4d3573e448af76ce33e16231f3d9f878542d6fe8" + integrity sha512-Jj0ieWLREPBYr/TZJrb2GFH8PVzDqiQWavo1pOFFShrcmHWDBDrlDxPzEZ67NF/Un3t6sNNmeI1TUS/fe1xARg== + +esbuild-freebsd-64@0.13.15: + version "0.13.15" + resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.13.15.tgz#0b8b7eca1690c8ec94c75680c38c07269c1f4a85" + integrity sha512-G3dLBXUI6lC6Z09/x+WtXBXbOYQZ0E8TDBqvn7aMaOCzryJs8LyVXKY4CPnHFXZAbSwkCbqiPuSQ1+HhrNk7EA== + +esbuild-freebsd-64@0.14.11: + version "0.14.11" + resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.11.tgz#9294e6ab359ec93590ab097b0f2017de7c78ab4d" + integrity sha512-C5sT3/XIztxxz/zwDjPRHyzj/NJFOnakAanXuyfLDwhwupKPd76/PPHHyJx6Po6NI6PomgVp/zi6GRB8PfrOTA== + +esbuild-freebsd-arm64@0.13.15: + version "0.13.15" + resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.13.15.tgz#2e1a6c696bfdcd20a99578b76350b41db1934e52" + integrity sha512-KJx0fzEDf1uhNOZQStV4ujg30WlnwqUASaGSFPhznLM/bbheu9HhqZ6mJJZM32lkyfGJikw0jg7v3S0oAvtvQQ== + +esbuild-freebsd-arm64@0.14.11: + version "0.14.11" + resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.11.tgz#ae3e0b09173350b66cf8321583c9a1c1fcb8bb55" + integrity sha512-y3Llu4wbs0bk4cwjsdAtVOesXb6JkdfZDLKMt+v1U3tOEPBdSu6w8796VTksJgPfqvpX22JmPLClls0h5p+L9w== + +esbuild-linux-32@0.13.15: + version "0.13.15" + resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.13.15.tgz#6fd39f36fc66dd45b6b5f515728c7bbebc342a69" + integrity sha512-ZvTBPk0YWCLMCXiFmD5EUtB30zIPvC5Itxz0mdTu/xZBbbHJftQgLWY49wEPSn2T/TxahYCRDWun5smRa0Tu+g== + +esbuild-linux-32@0.14.11: + version "0.14.11" + resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.11.tgz#ddadbc7038aa5a6b1675bb1503cf79a0cbf1229a" + integrity sha512-Cg3nVsxArjyLke9EuwictFF3Sva+UlDTwHIuIyx8qpxRYAOUTmxr2LzYrhHyTcGOleLGXUXYsnUVwKqnKAgkcg== + +esbuild-linux-64@0.13.15: + version "0.13.15" + resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.13.15.tgz#9cb8e4bcd7574e67946e4ee5f1f1e12386bb6dd3" + integrity sha512-eCKzkNSLywNeQTRBxJRQ0jxRCl2YWdMB3+PkWFo2BBQYC5mISLIVIjThNtn6HUNqua1pnvgP5xX0nHbZbPj5oA== + +esbuild-linux-64@0.14.11: + version "0.14.11" + resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.11.tgz#d698e3ce3a231ddfeec6b5df8c546ae8883fcd88" + integrity sha512-oeR6dIrrojr8DKVrxtH3xl4eencmjsgI6kPkDCRIIFwv4p+K7ySviM85K66BN01oLjzthpUMvBVfWSJkBLeRbg== + +esbuild-linux-arm64@0.13.15: + version "0.13.15" + resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.13.15.tgz#3891aa3704ec579a1b92d2a586122e5b6a2bfba1" + integrity sha512-bYpuUlN6qYU9slzr/ltyLTR9YTBS7qUDymO8SV7kjeNext61OdmqFAzuVZom+OLW1HPHseBfJ/JfdSlx8oTUoA== + +esbuild-linux-arm64@0.14.11: + version "0.14.11" + resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.11.tgz#85faea9fa99ad355b5e3b283197a4dfd0a110fe7" + integrity sha512-+e6ZCgTFQYZlmg2OqLkg1jHLYtkNDksxWDBWNtI4XG4WxuOCUErLqfEt9qWjvzK3XBcCzHImrajkUjO+rRkbMg== + +esbuild-linux-arm@0.13.15: + version "0.13.15" + resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.13.15.tgz#8a00e99e6a0c6c9a6b7f334841364d8a2b4aecfe" + integrity sha512-wUHttDi/ol0tD8ZgUMDH8Ef7IbDX+/UsWJOXaAyTdkT7Yy9ZBqPg8bgB/Dn3CZ9SBpNieozrPRHm0BGww7W/jA== + +esbuild-linux-arm@0.14.11: + version "0.14.11" + resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.11.tgz#74cbcf0b8a22c8401bcbcd6ebd4cbf2baca8b7b4" + integrity sha512-vcwskfD9g0tojux/ZaTJptJQU3a7YgTYsptK1y6LQ/rJmw7U5QJvboNawqM98Ca3ToYEucfCRGbl66OTNtp6KQ== + +esbuild-linux-mips64le@0.13.15: + version "0.13.15" + resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.13.15.tgz#36b07cc47c3d21e48db3bb1f4d9ef8f46aead4f7" + integrity sha512-KlVjIG828uFPyJkO/8gKwy9RbXhCEUeFsCGOJBepUlpa7G8/SeZgncUEz/tOOUJTcWMTmFMtdd3GElGyAtbSWg== + +esbuild-linux-mips64le@0.14.11: + version "0.14.11" + resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.11.tgz#490429211a3233f5cbbd8575b7758b897e42979a" + integrity sha512-Rrs99L+p54vepmXIb87xTG6ukrQv+CzrM8eoeR+r/OFL2Rg8RlyEtCeshXJ2+Q66MXZOgPJaokXJZb9snq28bw== + +esbuild-linux-ppc64le@0.13.15: + version "0.13.15" + resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.13.15.tgz#f7e6bba40b9a11eb9dcae5b01550ea04670edad2" + integrity sha512-h6gYF+OsaqEuBjeesTBtUPw0bmiDu7eAeuc2OEH9S6mV9/jPhPdhOWzdeshb0BskRZxPhxPOjqZ+/OqLcxQwEQ== + +esbuild-linux-ppc64le@0.14.11: + version "0.14.11" + resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.11.tgz#fc79d60710213b5b98345f5b138d48245616827a" + integrity sha512-JyzziGAI0D30Vyzt0HDihp4s1IUtJ3ssV2zx9O/c+U/dhUHVP2TmlYjzCfCr2Q6mwXTeloDcLS4qkyvJtYptdQ== + +esbuild-linux-s390x@0.14.11: + version "0.14.11" + resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.11.tgz#ca4b93556bbba6cc95b0644f2ee93c982165ba07" + integrity sha512-DoThrkzunZ1nfRGoDN6REwmo8ZZWHd2ztniPVIR5RMw/Il9wiWEYBahb8jnMzQaSOxBsGp0PbyJeVLTUatnlcw== + +esbuild-netbsd-64@0.13.15: + version "0.13.15" + resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.13.15.tgz#a2fedc549c2b629d580a732d840712b08d440038" + integrity sha512-3+yE9emwoevLMyvu+iR3rsa+Xwhie7ZEHMGDQ6dkqP/ndFzRHkobHUKTe+NCApSqG5ce2z4rFu+NX/UHnxlh3w== + +esbuild-netbsd-64@0.14.11: + version "0.14.11" + resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.11.tgz#edb340bc6653c88804cac2253e21b74258fce165" + integrity sha512-12luoRQz+6eihKYh1zjrw0CBa2aw3twIiHV/FAfjh2NEBDgJQOY4WCEUEN+Rgon7xmLh4XUxCQjnwrvf8zhACw== + +esbuild-openbsd-64@0.13.15: + version "0.13.15" + resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.13.15.tgz#b22c0e5806d3a1fbf0325872037f885306b05cd7" + integrity sha512-wTfvtwYJYAFL1fSs8yHIdf5GEE4NkbtbXtjLWjM3Cw8mmQKqsg8kTiqJ9NJQe5NX/5Qlo7Xd9r1yKMMkHllp5g== + +esbuild-openbsd-64@0.14.11: + version "0.14.11" + resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.11.tgz#caeff5f946f79a60ce7bcf88871ca4c71d3476e8" + integrity sha512-l18TZDjmvwW6cDeR4fmizNoxndyDHamGOOAenwI4SOJbzlJmwfr0jUgjbaXCUuYVOA964siw+Ix+A+bhALWg8Q== + +esbuild-sunos-64@0.13.15: + version "0.13.15" + resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.13.15.tgz#d0b6454a88375ee8d3964daeff55c85c91c7cef4" + integrity sha512-lbivT9Bx3t1iWWrSnGyBP9ODriEvWDRiweAs69vI+miJoeKwHWOComSRukttbuzjZ8r1q0mQJ8Z7yUsDJ3hKdw== + +esbuild-sunos-64@0.14.11: + version "0.14.11" + resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.11.tgz#90ce7e1749c2958a53509b4bae7b8f7d98f276d6" + integrity sha512-bmYzDtwASBB8c+0/HVOAiE9diR7+8zLm/i3kEojUH2z0aIs6x/S4KiTuT5/0VKJ4zk69kXel1cNWlHBMkmavQg== + +esbuild-windows-32@0.13.15: + version "0.13.15" + resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.13.15.tgz#c96d0b9bbb52f3303322582ef8e4847c5ad375a7" + integrity sha512-fDMEf2g3SsJ599MBr50cY5ve5lP1wyVwTe6aLJsM01KtxyKkB4UT+fc5MXQFn3RLrAIAZOG+tHC+yXObpSn7Nw== + +esbuild-windows-32@0.14.11: + version "0.14.11" + resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.11.tgz#d067f4ce15b29efba6336e6a23597120fafe49ec" + integrity sha512-J1Ys5hMid8QgdY00OBvIolXgCQn1ARhYtxPnG6ESWNTty3ashtc4+As5nTrsErnv8ZGUcWZe4WzTP/DmEVX1UQ== + +esbuild-windows-64@0.13.15: + version "0.13.15" + resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.13.15.tgz#1f79cb9b1e1bb02fb25cd414cb90d4ea2892c294" + integrity sha512-9aMsPRGDWCd3bGjUIKG/ZOJPKsiztlxl/Q3C1XDswO6eNX/Jtwu4M+jb6YDH9hRSUflQWX0XKAfWzgy5Wk54JQ== + +esbuild-windows-64@0.14.11: + version "0.14.11" + resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.11.tgz#13e86dd37a6cd61a5276fa2d271342d0f74da864" + integrity sha512-h9FmMskMuGeN/9G9+LlHPAoiQk9jlKDUn9yA0MpiGzwLa82E7r1b1u+h2a+InprbSnSLxDq/7p5YGtYVO85Mlg== + +esbuild-windows-arm64@0.13.15: + version "0.13.15" + resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.13.15.tgz#482173070810df22a752c686509c370c3be3b3c3" + integrity sha512-zzvyCVVpbwQQATaf3IG8mu1IwGEiDxKkYUdA4FpoCHi1KtPa13jeScYDjlW0Qh+ebWzpKfR2ZwvqAQkSWNcKjA== + +esbuild-windows-arm64@0.14.11: + version "0.14.11" + resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.11.tgz#e8edfdf1d712085e6dc3fba18a0c225aaae32b75" + integrity sha512-dZp7Krv13KpwKklt9/1vBFBMqxEQIO6ri7Azf8C+ob4zOegpJmha2XY9VVWP/OyQ0OWk6cEeIzMJwInRZrzBUQ== + +esbuild@^0.11.18: + version "0.11.23" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.11.23.tgz#c42534f632e165120671d64db67883634333b4b8" + integrity sha512-iaiZZ9vUF5wJV8ob1tl+5aJTrwDczlvGP0JoMmnpC2B0ppiMCu8n8gmy5ZTGl5bcG081XBVn+U+jP+mPFm5T5Q== + +esbuild@^0.13.12: + version "0.13.15" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.13.15.tgz#db56a88166ee373f87dbb2d8798ff449e0450cdf" + integrity sha512-raCxt02HBKv8RJxE8vkTSCXGIyKHdEdGfUmiYb8wnabnaEmHzyW7DCHb5tEN0xU8ryqg5xw54mcwnYkC4x3AIw== + optionalDependencies: + esbuild-android-arm64 "0.13.15" + esbuild-darwin-64 "0.13.15" + esbuild-darwin-arm64 "0.13.15" + esbuild-freebsd-64 "0.13.15" + esbuild-freebsd-arm64 "0.13.15" + esbuild-linux-32 "0.13.15" + esbuild-linux-64 "0.13.15" + esbuild-linux-arm "0.13.15" + esbuild-linux-arm64 "0.13.15" + esbuild-linux-mips64le "0.13.15" + esbuild-linux-ppc64le "0.13.15" + esbuild-netbsd-64 "0.13.15" + esbuild-openbsd-64 "0.13.15" + esbuild-sunos-64 "0.13.15" + esbuild-windows-32 "0.13.15" + esbuild-windows-64 "0.13.15" + esbuild-windows-arm64 "0.13.15" + +esbuild@^0.14.11: + version "0.14.11" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.14.11.tgz#ac4acb78907874832afb704c3afe58ad37715c27" + integrity sha512-xZvPtVj6yecnDeFb3KjjCM6i7B5TCAQZT77kkW/CpXTMnd6VLnRPKrUB1XHI1pSq6a4Zcy3BGueQ8VljqjDGCg== + optionalDependencies: + esbuild-android-arm64 "0.14.11" + esbuild-darwin-64 "0.14.11" + esbuild-darwin-arm64 "0.14.11" + esbuild-freebsd-64 "0.14.11" + esbuild-freebsd-arm64 "0.14.11" + esbuild-linux-32 "0.14.11" + esbuild-linux-64 "0.14.11" + esbuild-linux-arm "0.14.11" + esbuild-linux-arm64 "0.14.11" + esbuild-linux-mips64le "0.14.11" + esbuild-linux-ppc64le "0.14.11" + esbuild-linux-s390x "0.14.11" + esbuild-netbsd-64 "0.14.11" + esbuild-openbsd-64 "0.14.11" + esbuild-sunos-64 "0.14.11" + esbuild-windows-32 "0.14.11" + esbuild-windows-64 "0.14.11" + esbuild-windows-arm64 "0.14.11" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== escape-string-regexp@^1.0.5: version "1.0.5" @@ -2683,239 +2205,29 @@ escape-string-regexp@^2.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== -escodegen@^1.11.1: - version "1.14.3" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" - integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== +escodegen@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd" + integrity sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw== dependencies: esprima "^4.0.1" - estraverse "^4.2.0" + estraverse "^5.2.0" esutils "^2.0.2" optionator "^0.8.1" optionalDependencies: source-map "~0.6.1" -eslint-config-prettier@^6.0.0: - version "6.11.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.11.0.tgz#f6d2238c1290d01c859a8b5c1f7d352a0b0da8b1" - integrity sha512-oB8cpLWSAjOVFEJhhyMZh6NOEOtBVziaqdDQ86+qhDHFbZXoRTM7pNSvFRfW/W/L/LrQ38C99J5CGuRBBzBsdA== - dependencies: - get-stdin "^6.0.0" - -eslint-config-react-app@^5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/eslint-config-react-app/-/eslint-config-react-app-5.2.1.tgz#698bf7aeee27f0cea0139eaef261c7bf7dd623df" - integrity sha512-pGIZ8t0mFLcV+6ZirRgYK6RVqUIKRIi9MmgzUEmrIknsn3AdO0I32asO86dJgloHq+9ZPl8UIg8mYrvgP5u2wQ== - dependencies: - confusing-browser-globals "^1.0.9" - -eslint-import-resolver-node@^0.3.3: - version "0.3.4" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz#85ffa81942c25012d8231096ddf679c03042c717" - integrity sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA== - dependencies: - debug "^2.6.9" - resolve "^1.13.1" - -eslint-module-utils@^2.6.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz#579ebd094f56af7797d19c9866c9c9486629bfa6" - integrity sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA== - dependencies: - debug "^2.6.9" - pkg-dir "^2.0.0" - -eslint-plugin-flowtype@^3.13.0: - version "3.13.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-3.13.0.tgz#e241ebd39c0ce519345a3f074ec1ebde4cf80f2c" - integrity sha512-bhewp36P+t7cEV0b6OdmoRWJCBYRiHFlqPZAG1oS3SF+Y0LQkeDvFSM4oxoxvczD1OdONCXMlJfQFiWLcV9urw== - dependencies: - lodash "^4.17.15" - -eslint-plugin-import@^2.18.2: - version "2.22.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.22.0.tgz#92f7736fe1fde3e2de77623c838dd992ff5ffb7e" - integrity sha512-66Fpf1Ln6aIS5Gr/55ts19eUuoDhAbZgnr6UxK5hbDx6l/QgQgx61AePq+BV4PP2uXQFClgMVzep5zZ94qqsxg== - dependencies: - array-includes "^3.1.1" - array.prototype.flat "^1.2.3" - contains-path "^0.1.0" - debug "^2.6.9" - doctrine "1.5.0" - eslint-import-resolver-node "^0.3.3" - eslint-module-utils "^2.6.0" - has "^1.0.3" - minimatch "^3.0.4" - object.values "^1.1.1" - read-pkg-up "^2.0.0" - resolve "^1.17.0" - tsconfig-paths "^3.9.0" - -eslint-plugin-jsx-a11y@^6.2.3: - version "6.3.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.3.1.tgz#99ef7e97f567cc6a5b8dd5ab95a94a67058a2660" - integrity sha512-i1S+P+c3HOlBJzMFORRbC58tHa65Kbo8b52/TwCwSKLohwvpfT5rm2GjGWzOHTEuq4xxf2aRlHHTtmExDQOP+g== - dependencies: - "@babel/runtime" "^7.10.2" - aria-query "^4.2.2" - array-includes "^3.1.1" - ast-types-flow "^0.0.7" - axe-core "^3.5.4" - axobject-query "^2.1.2" - damerau-levenshtein "^1.0.6" - emoji-regex "^9.0.0" - has "^1.0.3" - jsx-ast-utils "^2.4.1" - language-tags "^1.0.5" - -eslint-plugin-prettier@^3.1.0: - version "3.1.4" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.4.tgz#168ab43154e2ea57db992a2cd097c828171f75c2" - integrity sha512-jZDa8z76klRqo+TdGDTFJSavwbnWK2ZpqGKNZ+VvweMW516pDUMmQ2koXvxEE4JhzNvTv+radye/bWGBmA6jmg== - dependencies: - prettier-linter-helpers "^1.0.0" - -eslint-plugin-react-hooks@^2.2.0: - version "2.5.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-2.5.1.tgz#4ef5930592588ce171abeb26f400c7fbcbc23cd0" - integrity sha512-Y2c4b55R+6ZzwtTppKwSmK/Kar8AdLiC2f9NADCuxbcTgPPg41Gyqa6b9GppgXSvCtkRw43ZE86CT5sejKC6/g== - -eslint-plugin-react@^7.14.3: - version "7.20.6" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.20.6.tgz#4d7845311a93c463493ccfa0a19c9c5d0fd69f60" - integrity sha512-kidMTE5HAEBSLu23CUDvj8dc3LdBU0ri1scwHBZjI41oDv4tjsWZKU7MQccFzH1QYPYhsnTF2ovh7JlcIcmxgg== - dependencies: - array-includes "^3.1.1" - array.prototype.flatmap "^1.2.3" - doctrine "^2.1.0" - has "^1.0.3" - jsx-ast-utils "^2.4.1" - object.entries "^1.1.2" - object.fromentries "^2.0.2" - object.values "^1.1.1" - prop-types "^15.7.2" - resolve "^1.17.0" - string.prototype.matchall "^4.0.2" - -eslint-scope@^5.0.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" - -eslint-utils@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" - integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== - dependencies: - eslint-visitor-keys "^1.1.0" - -eslint-utils@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" - integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== - dependencies: - eslint-visitor-keys "^1.1.0" - -eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" - integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== - -eslint@^6.1.0: - version "6.8.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.8.0.tgz#62262d6729739f9275723824302fb227c8c93ffb" - integrity sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig== - dependencies: - "@babel/code-frame" "^7.0.0" - ajv "^6.10.0" - chalk "^2.1.0" - cross-spawn "^6.0.5" - debug "^4.0.1" - doctrine "^3.0.0" - eslint-scope "^5.0.0" - eslint-utils "^1.4.3" - eslint-visitor-keys "^1.1.0" - espree "^6.1.2" - esquery "^1.0.1" - esutils "^2.0.2" - file-entry-cache "^5.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^5.0.0" - globals "^12.1.0" - ignore "^4.0.6" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - inquirer "^7.0.0" - is-glob "^4.0.0" - js-yaml "^3.13.1" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.3.0" - lodash "^4.17.14" - minimatch "^3.0.4" - mkdirp "^0.5.1" - natural-compare "^1.4.0" - optionator "^0.8.3" - progress "^2.0.0" - regexpp "^2.0.1" - semver "^6.1.2" - strip-ansi "^5.2.0" - strip-json-comments "^3.0.1" - table "^5.2.3" - text-table "^0.2.0" - v8-compile-cache "^2.0.3" - -espree@^6.1.2: - version "6.2.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-6.2.1.tgz#77fc72e1fd744a2052c20f38a5b575832e82734a" - integrity sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw== - dependencies: - acorn "^7.1.1" - acorn-jsx "^5.2.0" - eslint-visitor-keys "^1.1.0" - -esprima@^4.0.0, esprima@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -esquery@^1.0.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.3.1.tgz#b78b5828aa8e214e29fb74c4d5b752e1c033da57" - integrity sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ== - dependencies: - estraverse "^5.1.0" - -esrecurse@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - -estraverse@^4.1.1, estraverse@^4.2.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - -estraverse@^5.1.0, estraverse@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" - integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== - -estree-walker@^0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.6.1.tgz#53049143f40c6eb918b23671d1fe3219f3a1b362" - integrity sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w== +esprima@^4.0.0, esprima@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -estree-walker@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700" - integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg== +estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== -estree-walker@^2.0.1: +estree-walker@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== @@ -2926,9 +2238,9 @@ esutils@^2.0.2: integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== exec-sh@^0.3.2: - version "0.3.4" - resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.4.tgz#3a018ceb526cc6f6df2bb504b2bfe8e3a4934ec5" - integrity sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A== + version "0.3.6" + resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.6.tgz#ff264f9e325519a60cb5e273692943483cca63bc" + integrity sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w== execa@^1.0.0: version "1.0.0" @@ -2943,26 +2255,10 @@ execa@^1.0.0: signal-exit "^3.0.0" strip-eof "^1.0.0" -execa@^3.2.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-3.4.0.tgz#c08ed4550ef65d858fac269ffc8572446f37eb89" - integrity sha512-r9vdGQk4bmCuK1yKQu1KTwcT2zwfWdbdaXfCtAh+5nU/4fSX+JAb7vZGvI5naJrQlvONrEB20jeruESI69530g== - dependencies: - cross-spawn "^7.0.0" - get-stream "^5.0.0" - human-signals "^1.1.1" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.0" - onetime "^5.1.0" - p-finally "^2.0.0" - signal-exit "^3.0.2" - strip-final-newline "^2.0.0" - -execa@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/execa/-/execa-4.0.3.tgz#0a34dabbad6d66100bd6f2c576c8669403f317f2" - integrity sha512-WFDXGHckXPWZX19t1kCsXzOpqX9LWYNqn4C+HqZlk/V0imTkzJZqf87ZBhvpHaftERYknpk0fjSylnXVlVgI0A== +execa@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" + integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA== dependencies: cross-spawn "^7.0.0" get-stream "^5.0.0" @@ -3007,28 +2303,16 @@ expand-brackets@^2.1.4: snapdragon "^0.8.1" to-regex "^3.0.1" -expect@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/expect/-/expect-25.5.0.tgz#f07f848712a2813bb59167da3fb828ca21f58bba" - integrity sha512-w7KAXo0+6qqZZhovCaBVPSIqQp7/UTcx4M9uKt2m6pd2VB1voyC8JizLRqeEqud3AAVP02g+hbErDu5gu64tlA== - dependencies: - "@jest/types" "^25.5.0" - ansi-styles "^4.0.0" - jest-get-type "^25.2.6" - jest-matcher-utils "^25.5.0" - jest-message-util "^25.5.0" - jest-regex-util "^25.2.6" - -expect@^26.4.2: - version "26.4.2" - resolved "https://registry.yarnpkg.com/expect/-/expect-26.4.2.tgz#36db120928a5a2d7d9736643032de32f24e1b2a1" - integrity sha512-IlJ3X52Z0lDHm7gjEp+m76uX46ldH5VpqmU0006vqDju/285twh7zaWMRhs67VpQhBwjjMchk+p5aA0VkERCAA== +expect@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/expect/-/expect-26.6.2.tgz#c6b996bf26bf3fe18b67b2d0f51fc981ba934417" + integrity sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA== dependencies: - "@jest/types" "^26.3.0" + "@jest/types" "^26.6.2" ansi-styles "^4.0.0" jest-get-type "^26.3.0" - jest-matcher-utils "^26.4.2" - jest-message-util "^26.3.0" + jest-matcher-utils "^26.6.2" + jest-message-util "^26.6.2" jest-regex-util "^26.0.0" extend-shallow@^2.0.1: @@ -3046,20 +2330,6 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: assign-symbols "^1.0.0" is-extendable "^1.0.1" -extend@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - -external-editor@^3.0.3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" - integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== - dependencies: - chardet "^0.7.0" - iconv-lite "^0.4.24" - tmp "^0.0.33" - extglob@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" @@ -3074,27 +2344,7 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" -extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= - -extsprintf@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" - integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= - -fast-deep-equal@^3.1.1: - version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - -fast-diff@^1.1.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" - integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== - -fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: +fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== @@ -3111,20 +2361,6 @@ fb-watchman@^2.0.0: dependencies: bser "2.1.1" -figures@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" - integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== - dependencies: - escape-string-regexp "^1.0.5" - -file-entry-cache@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" - integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== - dependencies: - flat-cache "^2.0.1" - fill-range@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" @@ -3142,22 +2378,6 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" -find-cache-dir@^3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.1.tgz#89b33fad4a4670daa94f855f7fbe31d6d84fe880" - integrity sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ== - dependencies: - commondir "^1.0.1" - make-dir "^3.0.2" - pkg-dir "^4.1.0" - -find-up@^2.0.0, find-up@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= - dependencies: - locate-path "^2.0.0" - find-up@^4.0.0, find-up@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" @@ -3181,37 +2401,18 @@ find-versions@^4.0.0: dependencies: semver-regex "^3.1.2" -flat-cache@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" - integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== - dependencies: - flatted "^2.0.0" - rimraf "2.6.3" - write "1.0.3" - -flatted@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" - integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== - for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= - -form-data@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" - integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== +form-data@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" + integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== dependencies: asynckit "^0.4.0" - combined-stream "^1.0.6" + combined-stream "^1.0.8" mime-types "^2.1.12" fragment-cache@^0.2.1: @@ -3221,65 +2422,65 @@ fragment-cache@^0.2.1: dependencies: map-cache "^0.2.2" -fs-extra@8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" - integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== +framer-motion@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-6.0.0.tgz#08e44c42b67c967774a197b3994f8475cd486c32" + integrity sha512-wVI+hVRkvQeWSvkxk8z5bTg+jBs9vfEZOist2s0e9tQzZvt+OBuAoAcvCvl+ADmFd4ncC2934vkwiJPZ8nSvMg== dependencies: - graceful-fs "^4.2.0" - jsonfile "^4.0.0" - universalify "^0.1.0" + framesync "6.0.1" + hey-listen "^1.0.8" + popmotion "11.0.3" + style-value-types "5.0.0" + tslib "^2.1.0" + optionalDependencies: + "@emotion/is-prop-valid" "^0.8.2" -fs-extra@^9.0.0: - version "9.0.1" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.0.1.tgz#910da0062437ba4c39fedd863f1675ccfefcb9fc" - integrity sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ== +framesync@6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/framesync/-/framesync-6.0.1.tgz#5e32fc01f1c42b39c654c35b16440e07a25d6f20" + integrity sha512-fUY88kXvGiIItgNC7wcTOl0SNRCVXMKSWW2Yzfmn7EKNc+MpCzcz9DhdHcdjbrtN3c6R4H5dTY2jiCpPdysEjA== dependencies: - at-least-node "^1.0.0" - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^1.0.0" + tslib "^2.1.0" fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -fsevents@^2.1.2: - version "2.1.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e" - integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ== +fsevents@^2.1.2, fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= - -gensync@^1.0.0-beta.1: - version "1.0.0-beta.1" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" - integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== get-caller-file@^2.0.1: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== +get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" + integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + get-package-type@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== -get-stdin@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" - integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== - get-stream@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" @@ -3299,38 +2500,20 @@ get-stream@^6.0.0: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== +get-symbol-description@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" + integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= - dependencies: - assert-plus "^1.0.0" - -glob-parent@^5.0.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" - integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== - dependencies: - is-glob "^4.0.1" - -glob@^7.0.0, glob@^7.1.1, glob@^7.1.2, glob@^7.1.4, glob@^7.1.6: - version "7.1.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@^7.1.3: +glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: version "7.2.0" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== @@ -3347,45 +2530,20 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -globals@^12.1.0: - version "12.4.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" - integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== - dependencies: - type-fest "^0.8.1" - -globalyzer@^0.1.0: - version "0.1.4" - resolved "https://registry.yarnpkg.com/globalyzer/-/globalyzer-0.1.4.tgz#bc8e273afe1ac7c24eea8def5b802340c5cc534f" - integrity sha512-LeguVWaxgHN0MNbWC6YljNMzHkrCny9fzjmEUdnF1kQ7wATFD1RHFRqA1qxaX2tgxGENlcxjOflopBwj3YZiXA== - -globrex@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/globrex/-/globrex-0.1.2.tgz#dd5d9ec826232730cd6793a5e33a9302985e6098" - integrity sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg== - -graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: - version "4.2.4" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" - integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== +graceful-fs@^4.1.2, graceful-fs@^4.2.4: + version "4.2.9" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" + integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== growly@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= -har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= - -har-validator@~5.1.3: - version "5.1.5" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" - integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== - dependencies: - ajv "^6.12.3" - har-schema "^2.0.0" +has-bigints@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" + integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== has-flag@^3.0.0: version "3.0.0" @@ -3397,10 +2555,17 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-symbols@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" - integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== +has-symbols@^1.0.1, has-symbols@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" + integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== + +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" has-value@^0.3.1: version "0.3.1" @@ -3440,31 +2605,44 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" +hey-listen@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/hey-listen/-/hey-listen-1.0.8.tgz#8e59561ff724908de1aa924ed6ecc84a56a9aa68" + integrity sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q== + hosted-git-info@^2.1.4: - version "2.8.8" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" - integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== + version "2.8.9" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" + integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== -html-encoding-sniffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8" - integrity sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw== +html-encoding-sniffer@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" + integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ== dependencies: - whatwg-encoding "^1.0.1" + whatwg-encoding "^1.0.5" html-escaper@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== -http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= +http-proxy-agent@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" + integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" + "@tootallnate/once" "1" + agent-base "6" + debug "4" + +https-proxy-agent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" + integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== + dependencies: + agent-base "6" + debug "4" human-signals@^1.1.1: version "1.1.1" @@ -3476,11 +2654,6 @@ human-signals@^2.1.0: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== -humanize-duration@^3.15.3: - version "3.23.1" - resolved "https://registry.yarnpkg.com/humanize-duration/-/humanize-duration-3.23.1.tgz#59cb8d01287479c1aa7cd5b1efc260d799bef89b" - integrity sha512-aoOEkomAETmVuQyBx4E7/LfPlC9s8pAA/USl7vFRQpDjepo3aiyvFfOhtXSDqPowdBVPFUZ7onG/KyuolX0qPg== - husky@^4.3.8: version "4.3.8" resolved "https://registry.yarnpkg.com/husky/-/husky-4.3.8.tgz#31144060be963fd6850e5cc8f019a1dfe194296d" @@ -3497,26 +2670,13 @@ husky@^4.3.8: slash "^3.0.0" which-pm-runs "^1.0.0" -iconv-lite@0.4.24, iconv-lite@^0.4.24: +iconv-lite@0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== dependencies: safer-buffer ">= 2.1.2 < 3" -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - -import-fresh@^3.0.0, import-fresh@^3.1.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66" - integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - import-fresh@^3.2.1: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" @@ -3526,9 +2686,9 @@ import-fresh@^3.2.1: resolve-from "^4.0.0" import-local@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.0.2.tgz#a8cfd0431d1de4a2199703d003e3e62364fa6db6" - integrity sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA== + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== dependencies: pkg-dir "^4.2.0" resolve-cwd "^3.0.0" @@ -3551,7 +2711,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.4: +inherits@2, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -3561,50 +2721,14 @@ ini@^1.3.4: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== -inquirer@^7.0.0: - version "7.3.3" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003" - integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA== - dependencies: - ansi-escapes "^4.2.1" - chalk "^4.1.0" - cli-cursor "^3.1.0" - cli-width "^3.0.0" - external-editor "^3.0.3" - figures "^3.0.0" - lodash "^4.17.19" - mute-stream "0.0.8" - run-async "^2.4.0" - rxjs "^6.6.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - through "^2.3.6" - -internal-slot@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.2.tgz#9c2e9fb3cd8e5e4256c6f45fe310067fcfa378a3" - integrity sha512-2cQNfwhAfJIkU4KZPkDI+Gj5yNNnbqi40W9Gge6dfnk4TocEVm00B3bdiL+JINrbGJil2TeHvM4rETGzk/f/0g== +internal-slot@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" + integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== dependencies: - es-abstract "^1.17.0-next.1" + get-intrinsic "^1.1.0" has "^1.0.3" - side-channel "^1.0.2" - -interpret@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" - integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== - -invariant@^2.2.2, invariant@^2.2.4: - version "2.2.4" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" - integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== - dependencies: - loose-envify "^1.0.0" - -ip-regex@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" - integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= + side-channel "^1.0.4" is-accessor-descriptor@^0.1.6: version "0.1.6" @@ -3625,15 +2749,30 @@ is-arrayish@^0.2.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + is-buffer@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== -is-callable@^1.1.4, is-callable@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.1.tgz#4d1e21a4f437509d25ce55f8184350771421c96d" - integrity sha512-wliAfSzx6V+6WfMOmus1xy0XvSgf/dlStkvTfq7F0g4bOIW0PSUbnyse3NhDwdyYS1ozfUtAAySqTws3z9Eqgg== +is-callable@^1.1.4, is-callable@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" + integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== is-ci@^2.0.0: version "2.0.0" @@ -3642,6 +2781,13 @@ is-ci@^2.0.0: dependencies: ci-info "^2.0.0" +is-core-module@^2.8.0: + version "2.8.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211" + integrity sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA== + dependencies: + has "^1.0.3" + is-data-descriptor@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" @@ -3657,9 +2803,11 @@ is-data-descriptor@^1.0.0: kind-of "^6.0.0" is-date-object@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" - integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" is-descriptor@^0.1.0: version "0.1.6" @@ -3680,9 +2828,9 @@ is-descriptor@^1.0.0, is-descriptor@^1.0.2: kind-of "^6.0.2" is-docker@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.1.1.tgz#4125a88e44e450d384e09047ede71adc2d144156" - integrity sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw== + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" @@ -3696,16 +2844,6 @@ is-extendable@^1.0.1: dependencies: is-plain-object "^2.0.4" -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= - is-fullwidth-code-point@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" @@ -3721,27 +2859,17 @@ is-generator-fn@^2.0.0: resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== -is-glob@^4.0.0, is-glob@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" - integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== - dependencies: - is-extglob "^2.1.1" - -is-interactive@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" - integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== - -is-module@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" - integrity sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE= +is-negative-zero@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" + integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== -is-negative-zero@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.0.tgz#9553b121b0fac28869da9ed459e20c7543788461" - integrity sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE= +is-number-object@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.6.tgz#6a7aaf838c7f0686a50b4553f7e54a96494e89f0" + integrity sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g== + dependencies: + has-tostringtag "^1.0.0" is-number@^3.0.0: version "3.0.0" @@ -3762,19 +2890,23 @@ is-plain-object@^2.0.3, is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" -is-reference@^1.1.2: - version "1.2.1" - resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.2.1.tgz#8b2dac0b371f4bc994fdeaba9eb542d03002d0b7" - integrity sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ== - dependencies: - "@types/estree" "*" +is-potential-custom-element-name@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" + integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== -is-regex@^1.1.0, is-regex@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.1.tgz#c6f98aacc546f6cec5468a07b7b153ab564a57b9" - integrity sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg== +is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== dependencies: - has-symbols "^1.0.1" + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-shared-array-buffer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" + integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA== is-stream@^1.1.0: version "1.1.0" @@ -3786,23 +2918,32 @@ is-stream@^2.0.0: resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== -is-string@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6" - integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ== +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" -is-symbol@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" - integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== dependencies: - has-symbols "^1.0.1" + has-symbols "^1.0.2" -is-typedarray@^1.0.0, is-typedarray@~1.0.0: +is-typedarray@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= +is-weakref@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" + is-whitespace@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/is-whitespace/-/is-whitespace-0.3.0.tgz#1639ecb1be036aec69a54cbb401cfbed7114ab7f" @@ -3813,14 +2954,14 @@ is-windows@^1.0.2: resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== -is-wsl@^2.1.1: +is-wsl@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== dependencies: is-docker "^2.0.0" -isarray@1.0.0, isarray@^1.0.0: +isarray@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= @@ -3842,17 +2983,12 @@ isobject@^3.0.0, isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= - -istanbul-lib-coverage@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec" - integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg== +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" + integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== -istanbul-lib-instrument@^4.0.0: +istanbul-lib-instrument@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d" integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ== @@ -3862,6 +2998,17 @@ istanbul-lib-instrument@^4.0.0: istanbul-lib-coverage "^3.0.0" semver "^6.3.0" +istanbul-lib-instrument@^5.0.4: + version "5.1.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz#7b49198b657b27a730b8e9cb601f1e1bff24c59a" + integrity sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" + istanbul-lib-report@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" @@ -3872,95 +3019,83 @@ istanbul-lib-report@^3.0.0: supports-color "^7.1.0" istanbul-lib-source-maps@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz#75743ce6d96bb86dc7ee4352cf6366a23f0b1ad9" - integrity sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg== + version "4.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== dependencies: debug "^4.1.1" istanbul-lib-coverage "^3.0.0" source-map "^0.6.1" istanbul-reports@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.0.2.tgz#d593210e5000683750cb09fc0644e4b6e27fd53b" - integrity sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw== + version "3.1.3" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.3.tgz#4bcae3103b94518117930d51283690960b50d3c2" + integrity sha512-x9LtDVtfm/t1GFiLl3NffC7hz+I1ragvgX1P/Lg1NlIagifZDKUkuuaAxH/qpwj2IuEfD8G2Bs/UKp+sZ/pKkg== dependencies: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -jest-changed-files@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-25.5.0.tgz#141cc23567ceb3f534526f8614ba39421383634c" - integrity sha512-EOw9QEqapsDT7mKF162m8HFzRPbmP8qJQny6ldVOdOVBz3ACgPm/1nAn5fPQ/NDaYhX/AHkrGwwkCncpAVSXcw== +jest-changed-files@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-26.6.2.tgz#f6198479e1cc66f22f9ae1e22acaa0b429c042d0" + integrity sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ== dependencies: - "@jest/types" "^25.5.0" - execa "^3.2.0" + "@jest/types" "^26.6.2" + execa "^4.0.0" throat "^5.0.0" -jest-cli@^25.5.4: - version "25.5.4" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-25.5.4.tgz#b9f1a84d1301a92c5c217684cb79840831db9f0d" - integrity sha512-rG8uJkIiOUpnREh1768/N3n27Cm+xPFkSNFO91tgg+8o2rXeVLStz+vkXkGr4UtzH6t1SNbjwoiswd7p4AhHTw== +jest-cli@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-26.6.3.tgz#43117cfef24bc4cd691a174a8796a532e135e92a" + integrity sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg== dependencies: - "@jest/core" "^25.5.4" - "@jest/test-result" "^25.5.0" - "@jest/types" "^25.5.0" - chalk "^3.0.0" + "@jest/core" "^26.6.3" + "@jest/test-result" "^26.6.2" + "@jest/types" "^26.6.2" + chalk "^4.0.0" exit "^0.1.2" graceful-fs "^4.2.4" import-local "^3.0.2" is-ci "^2.0.0" - jest-config "^25.5.4" - jest-util "^25.5.0" - jest-validate "^25.5.0" + jest-config "^26.6.3" + jest-util "^26.6.2" + jest-validate "^26.6.2" prompts "^2.0.1" - realpath-native "^2.0.0" - yargs "^15.3.1" + yargs "^15.4.1" -jest-config@^25.5.4: - version "25.5.4" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-25.5.4.tgz#38e2057b3f976ef7309b2b2c8dcd2a708a67f02c" - integrity sha512-SZwR91SwcdK6bz7Gco8qL7YY2sx8tFJYzvg216DLihTWf+LKY/DoJXpM9nTzYakSyfblbqeU48p/p7Jzy05Atg== +jest-config@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-26.6.3.tgz#64f41444eef9eb03dc51d5c53b75c8c71f645349" + integrity sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg== dependencies: "@babel/core" "^7.1.0" - "@jest/test-sequencer" "^25.5.4" - "@jest/types" "^25.5.0" - babel-jest "^25.5.1" - chalk "^3.0.0" + "@jest/test-sequencer" "^26.6.3" + "@jest/types" "^26.6.2" + babel-jest "^26.6.3" + chalk "^4.0.0" deepmerge "^4.2.2" glob "^7.1.1" graceful-fs "^4.2.4" - jest-environment-jsdom "^25.5.0" - jest-environment-node "^25.5.0" - jest-get-type "^25.2.6" - jest-jasmine2 "^25.5.4" - jest-regex-util "^25.2.6" - jest-resolve "^25.5.1" - jest-util "^25.5.0" - jest-validate "^25.5.0" + jest-environment-jsdom "^26.6.2" + jest-environment-node "^26.6.2" + jest-get-type "^26.3.0" + jest-jasmine2 "^26.6.3" + jest-regex-util "^26.0.0" + jest-resolve "^26.6.2" + jest-util "^26.6.2" + jest-validate "^26.6.2" micromatch "^4.0.2" - pretty-format "^25.5.0" - realpath-native "^2.0.0" - -jest-diff@^25.2.1, jest-diff@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-25.5.0.tgz#1dd26ed64f96667c068cef026b677dfa01afcfa9" - integrity sha512-z1kygetuPiREYdNIumRpAHY6RXiGmp70YHptjdaxTWGmA085W3iCnXNx0DhflK3vwrKmrRWyY1wUpkPMVxMK7A== - dependencies: - chalk "^3.0.0" - diff-sequences "^25.2.6" - jest-get-type "^25.2.6" - pretty-format "^25.5.0" + pretty-format "^26.6.2" -jest-diff@^26.1.0, jest-diff@^26.4.2: - version "26.4.2" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.4.2.tgz#a1b7b303bcc534aabdb3bd4a7caf594ac059f5aa" - integrity sha512-6T1XQY8U28WH0Z5rGpQ+VqZSZz8EN8rZcBtfvXaOkbwxIEeRre6qnuZQlbY1AJ4MKDxQF8EkrCvK+hL/VkyYLQ== +jest-diff@^26.1.0, jest-diff@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.6.2.tgz#1aa7468b52c3a68d7d5c5fdcdfcd5e49bd164394" + integrity sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA== dependencies: chalk "^4.0.0" - diff-sequences "^26.3.0" + diff-sequences "^26.6.2" jest-get-type "^26.3.0" - pretty-format "^26.4.2" + pretty-format "^26.6.2" jest-diff@^27.0.0: version "27.4.6" @@ -3972,52 +3107,48 @@ jest-diff@^27.0.0: jest-get-type "^27.4.0" pretty-format "^27.4.6" -jest-docblock@^25.3.0: - version "25.3.0" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-25.3.0.tgz#8b777a27e3477cd77a168c05290c471a575623ef" - integrity sha512-aktF0kCar8+zxRHxQZwxMy70stc9R1mOmrLsT5VO3pIT0uzGRSDAXxSlz4NqQWpuLjPpuMhPRl7H+5FRsvIQAg== +jest-docblock@^26.0.0: + version "26.0.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-26.0.0.tgz#3e2fa20899fc928cb13bd0ff68bd3711a36889b5" + integrity sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w== dependencies: detect-newline "^3.0.0" -jest-each@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-25.5.0.tgz#0c3c2797e8225cb7bec7e4d249dcd96b934be516" - integrity sha512-QBogUxna3D8vtiItvn54xXde7+vuzqRrEeaw8r1s+1TG9eZLVJE5ZkKoSUlqFwRjnlaA4hyKGiu9OlkFIuKnjA== +jest-each@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-26.6.2.tgz#02526438a77a67401c8a6382dfe5999952c167cb" + integrity sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A== dependencies: - "@jest/types" "^25.5.0" - chalk "^3.0.0" - jest-get-type "^25.2.6" - jest-util "^25.5.0" - pretty-format "^25.5.0" - -jest-environment-jsdom@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-25.5.0.tgz#dcbe4da2ea997707997040ecf6e2560aec4e9834" - integrity sha512-7Jr02ydaq4jaWMZLY+Skn8wL5nVIYpWvmeatOHL3tOcV3Zw8sjnPpx+ZdeBfc457p8jCR9J6YCc+Lga0oIy62A== - dependencies: - "@jest/environment" "^25.5.0" - "@jest/fake-timers" "^25.5.0" - "@jest/types" "^25.5.0" - jest-mock "^25.5.0" - jest-util "^25.5.0" - jsdom "^15.2.1" - -jest-environment-node@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-25.5.0.tgz#0f55270d94804902988e64adca37c6ce0f7d07a1" - integrity sha512-iuxK6rQR2En9EID+2k+IBs5fCFd919gVVK5BeND82fYeLWPqvRcFNPKu9+gxTwfB5XwBGBvZ0HFQa+cHtIoslA== - dependencies: - "@jest/environment" "^25.5.0" - "@jest/fake-timers" "^25.5.0" - "@jest/types" "^25.5.0" - jest-mock "^25.5.0" - jest-util "^25.5.0" - semver "^6.3.0" + "@jest/types" "^26.6.2" + chalk "^4.0.0" + jest-get-type "^26.3.0" + jest-util "^26.6.2" + pretty-format "^26.6.2" + +jest-environment-jsdom@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz#78d09fe9cf019a357009b9b7e1f101d23bd1da3e" + integrity sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q== + dependencies: + "@jest/environment" "^26.6.2" + "@jest/fake-timers" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + jest-mock "^26.6.2" + jest-util "^26.6.2" + jsdom "^16.4.0" -jest-get-type@^25.2.6: - version "25.2.6" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-25.2.6.tgz#0b0a32fab8908b44d508be81681487dbabb8d877" - integrity sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig== +jest-environment-node@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-26.6.2.tgz#824e4c7fb4944646356f11ac75b229b0035f2b0c" + integrity sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag== + dependencies: + "@jest/environment" "^26.6.2" + "@jest/fake-timers" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + jest-mock "^26.6.2" + jest-util "^26.6.2" jest-get-type@^26.3.0: version "26.3.0" @@ -4029,398 +3160,277 @@ jest-get-type@^27.4.0: resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.4.0.tgz#7503d2663fffa431638337b3998d39c5e928e9b5" integrity sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ== -jest-haste-map@^25.5.1: - version "25.5.1" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-25.5.1.tgz#1df10f716c1d94e60a1ebf7798c9fb3da2620943" - integrity sha512-dddgh9UZjV7SCDQUrQ+5t9yy8iEgKc1AKqZR9YDww8xsVOtzPQSMVLDChc21+g29oTRexb9/B0bIlZL+sWmvAQ== - dependencies: - "@jest/types" "^25.5.0" - "@types/graceful-fs" "^4.1.2" - anymatch "^3.0.3" - fb-watchman "^2.0.0" - graceful-fs "^4.2.4" - jest-serializer "^25.5.0" - jest-util "^25.5.0" - jest-worker "^25.5.0" - micromatch "^4.0.2" - sane "^4.0.3" - walker "^1.0.7" - which "^2.0.2" - optionalDependencies: - fsevents "^2.1.2" - -jest-haste-map@^26.3.0: - version "26.3.0" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-26.3.0.tgz#c51a3b40100d53ab777bfdad382d2e7a00e5c726" - integrity sha512-DHWBpTJgJhLLGwE5Z1ZaqLTYqeODQIZpby0zMBsCU9iRFHYyhklYqP4EiG73j5dkbaAdSZhgB938mL51Q5LeZA== +jest-haste-map@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-26.6.2.tgz#dd7e60fe7dc0e9f911a23d79c5ff7fb5c2cafeaa" + integrity sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w== dependencies: - "@jest/types" "^26.3.0" + "@jest/types" "^26.6.2" "@types/graceful-fs" "^4.1.2" "@types/node" "*" anymatch "^3.0.3" fb-watchman "^2.0.0" graceful-fs "^4.2.4" jest-regex-util "^26.0.0" - jest-serializer "^26.3.0" - jest-util "^26.3.0" - jest-worker "^26.3.0" + jest-serializer "^26.6.2" + jest-util "^26.6.2" + jest-worker "^26.6.2" micromatch "^4.0.2" sane "^4.0.3" walker "^1.0.7" optionalDependencies: fsevents "^2.1.2" -jest-jasmine2@^25.5.4: - version "25.5.4" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-25.5.4.tgz#66ca8b328fb1a3c5364816f8958f6970a8526968" - integrity sha512-9acbWEfbmS8UpdcfqnDO+uBUgKa/9hcRh983IHdM+pKmJPL77G0sWAAK0V0kr5LK3a8cSBfkFSoncXwQlRZfkQ== +jest-jasmine2@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz#adc3cf915deacb5212c93b9f3547cd12958f2edd" + integrity sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg== dependencies: "@babel/traverse" "^7.1.0" - "@jest/environment" "^25.5.0" - "@jest/source-map" "^25.5.0" - "@jest/test-result" "^25.5.0" - "@jest/types" "^25.5.0" - chalk "^3.0.0" + "@jest/environment" "^26.6.2" + "@jest/source-map" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + chalk "^4.0.0" co "^4.6.0" - expect "^25.5.0" + expect "^26.6.2" is-generator-fn "^2.0.0" - jest-each "^25.5.0" - jest-matcher-utils "^25.5.0" - jest-message-util "^25.5.0" - jest-runtime "^25.5.4" - jest-snapshot "^25.5.1" - jest-util "^25.5.0" - pretty-format "^25.5.0" + jest-each "^26.6.2" + jest-matcher-utils "^26.6.2" + jest-message-util "^26.6.2" + jest-runtime "^26.6.3" + jest-snapshot "^26.6.2" + jest-util "^26.6.2" + pretty-format "^26.6.2" throat "^5.0.0" -jest-leak-detector@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-25.5.0.tgz#2291c6294b0ce404241bb56fe60e2d0c3e34f0bb" - integrity sha512-rV7JdLsanS8OkdDpZtgBf61L5xZ4NnYLBq72r6ldxahJWWczZjXawRsoHyXzibM5ed7C2QRjpp6ypgwGdKyoVA== - dependencies: - jest-get-type "^25.2.6" - pretty-format "^25.5.0" - -jest-matcher-utils@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-25.5.0.tgz#fbc98a12d730e5d2453d7f1ed4a4d948e34b7867" - integrity sha512-VWI269+9JS5cpndnpCwm7dy7JtGQT30UHfrnM3mXl22gHGt/b7NkjBqXfbhZ8V4B7ANUsjK18PlSBmG0YH7gjw== - dependencies: - chalk "^3.0.0" - jest-diff "^25.5.0" - jest-get-type "^25.2.6" - pretty-format "^25.5.0" - -jest-matcher-utils@^26.4.2: - version "26.4.2" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-26.4.2.tgz#fa81f3693f7cb67e5fc1537317525ef3b85f4b06" - integrity sha512-KcbNqWfWUG24R7tu9WcAOKKdiXiXCbMvQYT6iodZ9k1f7065k0keUOW6XpJMMvah+hTfqkhJhRXmA3r3zMAg0Q== +jest-leak-detector@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz#7717cf118b92238f2eba65054c8a0c9c653a91af" + integrity sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg== dependencies: - chalk "^4.0.0" - jest-diff "^26.4.2" jest-get-type "^26.3.0" - pretty-format "^26.4.2" + pretty-format "^26.6.2" -jest-message-util@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-25.5.0.tgz#ea11d93204cc7ae97456e1d8716251185b8880ea" - integrity sha512-ezddz3YCT/LT0SKAmylVyWWIGYoKHOFOFXx3/nA4m794lfVUskMcwhip6vTgdVrOtYdjeQeis2ypzes9mZb4EA== +jest-matcher-utils@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz#8e6fd6e863c8b2d31ac6472eeb237bc595e53e7a" + integrity sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw== dependencies: - "@babel/code-frame" "^7.0.0" - "@jest/types" "^25.5.0" - "@types/stack-utils" "^1.0.1" - chalk "^3.0.0" - graceful-fs "^4.2.4" - micromatch "^4.0.2" - slash "^3.0.0" - stack-utils "^1.0.1" + chalk "^4.0.0" + jest-diff "^26.6.2" + jest-get-type "^26.3.0" + pretty-format "^26.6.2" -jest-message-util@^26.3.0: - version "26.3.0" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-26.3.0.tgz#3bdb538af27bb417f2d4d16557606fd082d5841a" - integrity sha512-xIavRYqr4/otGOiLxLZGj3ieMmjcNE73Ui+LdSW/Y790j5acqCsAdDiLIbzHCZMpN07JOENRWX5DcU+OQ+TjTA== +jest-message-util@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-26.6.2.tgz#58173744ad6fc0506b5d21150b9be56ef001ca07" + integrity sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA== dependencies: "@babel/code-frame" "^7.0.0" - "@jest/types" "^26.3.0" - "@types/stack-utils" "^1.0.1" + "@jest/types" "^26.6.2" + "@types/stack-utils" "^2.0.0" chalk "^4.0.0" graceful-fs "^4.2.4" micromatch "^4.0.2" + pretty-format "^26.6.2" slash "^3.0.0" stack-utils "^2.0.2" -jest-mock@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-25.5.0.tgz#a91a54dabd14e37ecd61665d6b6e06360a55387a" - integrity sha512-eXWuTV8mKzp/ovHc5+3USJMYsTBhyQ+5A1Mak35dey/RG8GlM4YWVylZuGgVXinaW6tpvk/RSecmF37FKUlpXA== +jest-mock@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-26.6.2.tgz#d6cb712b041ed47fe0d9b6fc3474bc6543feb302" + integrity sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew== dependencies: - "@jest/types" "^25.5.0" + "@jest/types" "^26.6.2" + "@types/node" "*" -jest-pnp-resolver@^1.2.1, jest-pnp-resolver@^1.2.2: +jest-pnp-resolver@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== -jest-regex-util@^25.2.1, jest-regex-util@^25.2.6: - version "25.2.6" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-25.2.6.tgz#d847d38ba15d2118d3b06390056028d0f2fd3964" - integrity sha512-KQqf7a0NrtCkYmZZzodPftn7fL1cq3GQAFVMn5Hg8uKx/fIenLEobNanUxb7abQ1sjADHBseG/2FGpsv/wr+Qw== - jest-regex-util@^26.0.0: version "26.0.0" resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28" integrity sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A== -jest-resolve-dependencies@^25.5.4: - version "25.5.4" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-25.5.4.tgz#85501f53957c8e3be446e863a74777b5a17397a7" - integrity sha512-yFmbPd+DAQjJQg88HveObcGBA32nqNZ02fjYmtL16t1xw9bAttSn5UGRRhzMHIQbsep7znWvAvnD4kDqOFM0Uw== +jest-resolve-dependencies@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz#6680859ee5d22ee5dcd961fe4871f59f4c784fb6" + integrity sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg== dependencies: - "@jest/types" "^25.5.0" - jest-regex-util "^25.2.6" - jest-snapshot "^25.5.1" - -jest-resolve@^25.5.1: - version "25.5.1" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-25.5.1.tgz#0e6fbcfa7c26d2a5fe8f456088dc332a79266829" - integrity sha512-Hc09hYch5aWdtejsUZhA+vSzcotf7fajSlPA6EZPE1RmPBAD39XtJhvHWFStid58iit4IPDLI/Da4cwdDmAHiQ== - dependencies: - "@jest/types" "^25.5.0" - browser-resolve "^1.11.3" - chalk "^3.0.0" - graceful-fs "^4.2.4" - jest-pnp-resolver "^1.2.1" - read-pkg-up "^7.0.1" - realpath-native "^2.0.0" - resolve "^1.17.0" - slash "^3.0.0" + "@jest/types" "^26.6.2" + jest-regex-util "^26.0.0" + jest-snapshot "^26.6.2" -jest-resolve@^26.4.0: - version "26.4.0" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-26.4.0.tgz#6dc0af7fb93e65b73fec0368ca2b76f3eb59a6d7" - integrity sha512-bn/JoZTEXRSlEx3+SfgZcJAVuTMOksYq9xe9O6s4Ekg84aKBObEaVXKOEilULRqviSLAYJldnoWV9c07kwtiCg== +jest-resolve@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-26.6.2.tgz#a3ab1517217f469b504f1b56603c5bb541fbb507" + integrity sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ== dependencies: - "@jest/types" "^26.3.0" + "@jest/types" "^26.6.2" chalk "^4.0.0" graceful-fs "^4.2.4" jest-pnp-resolver "^1.2.2" - jest-util "^26.3.0" + jest-util "^26.6.2" read-pkg-up "^7.0.1" - resolve "^1.17.0" + resolve "^1.18.1" slash "^3.0.0" -jest-runner@^25.5.4: - version "25.5.4" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-25.5.4.tgz#ffec5df3875da5f5c878ae6d0a17b8e4ecd7c71d" - integrity sha512-V/2R7fKZo6blP8E9BL9vJ8aTU4TH2beuqGNxHbxi6t14XzTb+x90B3FRgdvuHm41GY8ch4xxvf0ATH4hdpjTqg== +jest-runner@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-26.6.3.tgz#2d1fed3d46e10f233fd1dbd3bfaa3fe8924be159" + integrity sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ== dependencies: - "@jest/console" "^25.5.0" - "@jest/environment" "^25.5.0" - "@jest/test-result" "^25.5.0" - "@jest/types" "^25.5.0" - chalk "^3.0.0" + "@jest/console" "^26.6.2" + "@jest/environment" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.7.1" exit "^0.1.2" graceful-fs "^4.2.4" - jest-config "^25.5.4" - jest-docblock "^25.3.0" - jest-haste-map "^25.5.1" - jest-jasmine2 "^25.5.4" - jest-leak-detector "^25.5.0" - jest-message-util "^25.5.0" - jest-resolve "^25.5.1" - jest-runtime "^25.5.4" - jest-util "^25.5.0" - jest-worker "^25.5.0" + jest-config "^26.6.3" + jest-docblock "^26.0.0" + jest-haste-map "^26.6.2" + jest-leak-detector "^26.6.2" + jest-message-util "^26.6.2" + jest-resolve "^26.6.2" + jest-runtime "^26.6.3" + jest-util "^26.6.2" + jest-worker "^26.6.2" source-map-support "^0.5.6" throat "^5.0.0" -jest-runtime@^25.5.4: - version "25.5.4" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-25.5.4.tgz#dc981fe2cb2137abcd319e74ccae7f7eeffbfaab" - integrity sha512-RWTt8LeWh3GvjYtASH2eezkc8AehVoWKK20udV6n3/gC87wlTbE1kIA+opCvNWyyPeBs6ptYsc6nyHUb1GlUVQ== - dependencies: - "@jest/console" "^25.5.0" - "@jest/environment" "^25.5.0" - "@jest/globals" "^25.5.2" - "@jest/source-map" "^25.5.0" - "@jest/test-result" "^25.5.0" - "@jest/transform" "^25.5.1" - "@jest/types" "^25.5.0" +jest-runtime@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-26.6.3.tgz#4f64efbcfac398331b74b4b3c82d27d401b8fa2b" + integrity sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw== + dependencies: + "@jest/console" "^26.6.2" + "@jest/environment" "^26.6.2" + "@jest/fake-timers" "^26.6.2" + "@jest/globals" "^26.6.2" + "@jest/source-map" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/transform" "^26.6.2" + "@jest/types" "^26.6.2" "@types/yargs" "^15.0.0" - chalk "^3.0.0" + chalk "^4.0.0" + cjs-module-lexer "^0.6.0" collect-v8-coverage "^1.0.0" exit "^0.1.2" glob "^7.1.3" graceful-fs "^4.2.4" - jest-config "^25.5.4" - jest-haste-map "^25.5.1" - jest-message-util "^25.5.0" - jest-mock "^25.5.0" - jest-regex-util "^25.2.6" - jest-resolve "^25.5.1" - jest-snapshot "^25.5.1" - jest-util "^25.5.0" - jest-validate "^25.5.0" - realpath-native "^2.0.0" + jest-config "^26.6.3" + jest-haste-map "^26.6.2" + jest-message-util "^26.6.2" + jest-mock "^26.6.2" + jest-regex-util "^26.0.0" + jest-resolve "^26.6.2" + jest-snapshot "^26.6.2" + jest-util "^26.6.2" + jest-validate "^26.6.2" slash "^3.0.0" strip-bom "^4.0.0" - yargs "^15.3.1" - -jest-serializer@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-25.5.0.tgz#a993f484e769b4ed54e70e0efdb74007f503072b" - integrity sha512-LxD8fY1lByomEPflwur9o4e2a5twSQ7TaVNLlFUuToIdoJuBt8tzHfCsZ42Ok6LkKXWzFWf3AGmheuLAA7LcCA== - dependencies: - graceful-fs "^4.2.4" + yargs "^15.4.1" -jest-serializer@^26.3.0: - version "26.3.0" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-26.3.0.tgz#1c9d5e1b74d6e5f7e7f9627080fa205d976c33ef" - integrity sha512-IDRBQBLPlKa4flg77fqg0n/pH87tcRKwe8zxOVTWISxGpPHYkRZ1dXKyh04JOja7gppc60+soKVZ791mruVdow== +jest-serializer@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-26.6.2.tgz#d139aafd46957d3a448f3a6cdabe2919ba0742d1" + integrity sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g== dependencies: "@types/node" "*" graceful-fs "^4.2.4" -jest-snapshot@^25.5.1: - version "25.5.1" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-25.5.1.tgz#1a2a576491f9961eb8d00c2e5fd479bc28e5ff7f" - integrity sha512-C02JE1TUe64p2v1auUJ2ze5vcuv32tkv9PyhEb318e8XOKF7MOyXdJ7kdjbvrp3ChPLU2usI7Rjxs97Dj5P0uQ== - dependencies: - "@babel/types" "^7.0.0" - "@jest/types" "^25.5.0" - "@types/prettier" "^1.19.0" - chalk "^3.0.0" - expect "^25.5.0" - graceful-fs "^4.2.4" - jest-diff "^25.5.0" - jest-get-type "^25.2.6" - jest-matcher-utils "^25.5.0" - jest-message-util "^25.5.0" - jest-resolve "^25.5.1" - make-dir "^3.0.0" - natural-compare "^1.4.0" - pretty-format "^25.5.0" - semver "^6.3.0" - -jest-snapshot@^26.1.0: - version "26.4.2" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-26.4.2.tgz#87d3ac2f2bd87ea8003602fbebd8fcb9e94104f6" - integrity sha512-N6Uub8FccKlf5SBFnL2Ri/xofbaA68Cc3MGjP/NuwgnsvWh+9hLIR/DhrxbSiKXMY9vUW5dI6EW1eHaDHqe9sg== +jest-snapshot@^26.1.0, jest-snapshot@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-26.6.2.tgz#f3b0af1acb223316850bd14e1beea9837fb39c84" + integrity sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og== dependencies: "@babel/types" "^7.0.0" - "@jest/types" "^26.3.0" + "@jest/types" "^26.6.2" + "@types/babel__traverse" "^7.0.4" "@types/prettier" "^2.0.0" chalk "^4.0.0" - expect "^26.4.2" + expect "^26.6.2" graceful-fs "^4.2.4" - jest-diff "^26.4.2" + jest-diff "^26.6.2" jest-get-type "^26.3.0" - jest-haste-map "^26.3.0" - jest-matcher-utils "^26.4.2" - jest-message-util "^26.3.0" - jest-resolve "^26.4.0" + jest-haste-map "^26.6.2" + jest-matcher-utils "^26.6.2" + jest-message-util "^26.6.2" + jest-resolve "^26.6.2" natural-compare "^1.4.0" - pretty-format "^26.4.2" + pretty-format "^26.6.2" semver "^7.3.2" -jest-util@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-25.5.0.tgz#31c63b5d6e901274d264a4fec849230aa3fa35b0" - integrity sha512-KVlX+WWg1zUTB9ktvhsg2PXZVdkI1NBevOJSkTKYAyXyH4QSvh+Lay/e/v+bmaFfrkfx43xD8QTfgobzlEXdIA== - dependencies: - "@jest/types" "^25.5.0" - chalk "^3.0.0" - graceful-fs "^4.2.4" - is-ci "^2.0.0" - make-dir "^3.0.0" - -jest-util@^26.3.0: - version "26.3.0" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.3.0.tgz#a8974b191df30e2bf523ebbfdbaeb8efca535b3e" - integrity sha512-4zpn6bwV0+AMFN0IYhH/wnzIQzRaYVrz1A8sYnRnj4UXDXbOVtWmlaZkO9mipFqZ13okIfN87aDoJWB7VH6hcw== +jest-util@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.6.2.tgz#907535dbe4d5a6cb4c47ac9b926f6af29576cbc1" + integrity sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q== dependencies: - "@jest/types" "^26.3.0" + "@jest/types" "^26.6.2" "@types/node" "*" chalk "^4.0.0" graceful-fs "^4.2.4" is-ci "^2.0.0" micromatch "^4.0.2" -jest-validate@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-25.5.0.tgz#fb4c93f332c2e4cf70151a628e58a35e459a413a" - integrity sha512-okUFKqhZIpo3jDdtUXUZ2LxGUZJIlfdYBvZb1aczzxrlyMlqdnnws9MOxezoLGhSaFc2XYaHNReNQfj5zPIWyQ== +jest-validate@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-26.6.2.tgz#23d380971587150467342911c3d7b4ac57ab20ec" + integrity sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ== dependencies: - "@jest/types" "^25.5.0" - camelcase "^5.3.1" - chalk "^3.0.0" - jest-get-type "^25.2.6" + "@jest/types" "^26.6.2" + camelcase "^6.0.0" + chalk "^4.0.0" + jest-get-type "^26.3.0" leven "^3.1.0" - pretty-format "^25.5.0" - -jest-watch-typeahead@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/jest-watch-typeahead/-/jest-watch-typeahead-0.5.0.tgz#903dba6112f22daae7e90b0a271853f7ff182008" - integrity sha512-4r36w9vU8+rdg48hj0Z7TvcSqVP6Ao8dk04grlHQNgduyCB0SqrI0xWIl85ZhXrzYvxQ0N5H+rRLAejkQzEHeQ== - dependencies: - ansi-escapes "^4.2.1" - chalk "^3.0.0" - jest-regex-util "^25.2.1" - jest-watcher "^25.2.4" - slash "^3.0.0" - string-length "^3.1.0" - strip-ansi "^6.0.0" + pretty-format "^26.6.2" -jest-watcher@^25.2.4, jest-watcher@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-25.5.0.tgz#d6110d101df98badebe435003956fd4a465e8456" - integrity sha512-XrSfJnVASEl+5+bb51V0Q7WQx65dTSk7NL4yDdVjPnRNpM0hG+ncFmDYJo9O8jaSRcAitVbuVawyXCRoxGrT5Q== +jest-watcher@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-26.6.2.tgz#a5b683b8f9d68dbcb1d7dae32172d2cca0592975" + integrity sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ== dependencies: - "@jest/test-result" "^25.5.0" - "@jest/types" "^25.5.0" + "@jest/test-result" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" ansi-escapes "^4.2.1" - chalk "^3.0.0" - jest-util "^25.5.0" - string-length "^3.1.0" - -jest-worker@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.9.0.tgz#5dbfdb5b2d322e98567898238a9697bcce67b3e5" - integrity sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw== - dependencies: - merge-stream "^2.0.0" - supports-color "^6.1.0" + chalk "^4.0.0" + jest-util "^26.6.2" + string-length "^4.0.1" -jest-worker@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-25.5.0.tgz#2611d071b79cea0f43ee57a3d118593ac1547db1" - integrity sha512-/dsSmUkIy5EBGfv/IjjqmFxrNAUpBERfGs1oHROyD7yxjG/w+t0GOJDX8O1k32ySmd7+a5IhnJU2qQFcJ4n1vw== +jest-worker@27.0.0-next.5: + version "27.0.0-next.5" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.0.0-next.5.tgz#5985ee29b12a4e191f4aae4bb73b97971d86ec28" + integrity sha512-mk0umAQ5lT+CaOJ+Qp01N6kz48sJG2kr2n1rX0koqKf6FIygQV0qLOdN9SCYID4IVeSigDOcPeGLozdMLYfb5g== dependencies: + "@types/node" "*" merge-stream "^2.0.0" - supports-color "^7.0.0" + supports-color "^8.0.0" -jest-worker@^26.3.0: - version "26.3.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.3.0.tgz#7c8a97e4f4364b4f05ed8bca8ca0c24de091871f" - integrity sha512-Vmpn2F6IASefL+DVBhPzI2J9/GJUsqzomdeN+P+dK8/jKxbh8R3BtFnx3FIta7wYlPU62cpJMJQo4kuOowcMnw== +jest-worker@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" + integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ== dependencies: "@types/node" "*" merge-stream "^2.0.0" supports-color "^7.0.0" -jest@^25.3.0: - version "25.5.4" - resolved "https://registry.yarnpkg.com/jest/-/jest-25.5.4.tgz#f21107b6489cfe32b076ce2adcadee3587acb9db" - integrity sha512-hHFJROBTqZahnO+X+PMtT6G2/ztqAZJveGqz//FnWWHurizkD05PQGzRZOhF3XP6z7SJmL+5tCfW8qV06JypwQ== +jest@26: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest/-/jest-26.6.3.tgz#40e8fdbe48f00dfa1f0ce8121ca74b88ac9148ef" + integrity sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q== dependencies: - "@jest/core" "^25.5.4" + "@jest/core" "^26.6.3" import-local "^3.0.2" - jest-cli "^25.5.4" - -jpjs@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/jpjs/-/jpjs-1.2.1.tgz#f343833de8838a5beba1f42d5a219be0114c44b7" - integrity sha512-GxJWybWU4NV0RNKi6EIqk6IRPOTqd/h+U7sbtyuD7yUISUzV78LdHnq2xkevJsTlz/EImux4sWj+wfMiwKLkiw== + jest-cli "^26.6.3" js-beautify@^1.6.12: version "1.14.0" @@ -4438,48 +3448,44 @@ js-beautify@^1.6.12: integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== js-yaml@^3.13.1: - version "3.14.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482" - integrity sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A== + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== dependencies: argparse "^1.0.7" esprima "^4.0.0" -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= - -jsdom@^15.2.1: - version "15.2.1" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-15.2.1.tgz#d2feb1aef7183f86be521b8c6833ff5296d07ec5" - integrity sha512-fAl1W0/7T2G5vURSyxBzrJ1LSdQn6Tr5UX/xD4PXDx/PDgwygedfW6El/KIj3xJ7FU61TTYnc/l/B7P49Eqt6g== - dependencies: - abab "^2.0.0" - acorn "^7.1.0" - acorn-globals "^4.3.2" - array-equal "^1.0.0" - cssom "^0.4.1" - cssstyle "^2.0.0" - data-urls "^1.1.0" - domexception "^1.0.1" - escodegen "^1.11.1" - html-encoding-sniffer "^1.0.2" +jsdom@^16.4.0: + version "16.7.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" + integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw== + dependencies: + abab "^2.0.5" + acorn "^8.2.4" + acorn-globals "^6.0.0" + cssom "^0.4.4" + cssstyle "^2.3.0" + data-urls "^2.0.0" + decimal.js "^10.2.1" + domexception "^2.0.1" + escodegen "^2.0.0" + form-data "^3.0.0" + html-encoding-sniffer "^2.0.1" + http-proxy-agent "^4.0.1" + https-proxy-agent "^5.0.0" + is-potential-custom-element-name "^1.0.1" nwsapi "^2.2.0" - parse5 "5.1.0" - pn "^1.1.0" - request "^2.88.0" - request-promise-native "^1.0.7" - saxes "^3.1.9" - symbol-tree "^3.2.2" - tough-cookie "^3.0.1" - w3c-hr-time "^1.0.1" - w3c-xmlserializer "^1.1.2" - webidl-conversions "^4.0.2" + parse5 "6.0.1" + saxes "^5.0.1" + symbol-tree "^3.2.4" + tough-cookie "^4.0.0" + w3c-hr-time "^1.0.2" + w3c-xmlserializer "^2.0.0" + webidl-conversions "^6.1.0" whatwg-encoding "^1.0.5" whatwg-mimetype "^2.3.0" - whatwg-url "^7.0.0" - ws "^7.0.0" + whatwg-url "^8.5.0" + ws "^7.4.6" xml-name-validator "^3.0.0" jsesc@^2.5.1: @@ -4487,43 +3493,16 @@ jsesc@^2.5.1: resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== -jsesc@~0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" - integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= +json-parse-better-errors@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== json-parse-even-better-errors@^2.3.0: version "2.3.1" resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= - -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= - -json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= - -json5@2.x, json5@^2.1.2: - version "2.1.3" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" - integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== - dependencies: - minimist "^1.2.5" - json5@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" @@ -4531,39 +3510,12 @@ json5@^1.0.1: dependencies: minimist "^1.2.0" -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= - optionalDependencies: - graceful-fs "^4.1.6" - -jsonfile@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.0.1.tgz#98966cba214378c8c84b82e085907b40bf614179" - integrity sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg== - dependencies: - universalify "^1.0.0" - optionalDependencies: - graceful-fs "^4.1.6" - -jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.2.3" - verror "1.10.0" - -jsx-ast-utils@^2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.4.1.tgz#1114a4c1209481db06c690c2b4f488cc665f657e" - integrity sha512-z1xSldJ6imESSzOjd3NNkieVJKRlKYSOtMG8SFyCj2FIrvSaSuli/WjpBkEzCBoR9bYYYFgqJw61Xhu7Lcgk+w== +json5@^2.1.2: + version "2.2.0" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" + integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== dependencies: - array-includes "^3.1.1" - object.assign "^4.1.0" + minimist "^1.2.5" kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" @@ -4594,31 +3546,12 @@ kleur@^3.0.3: resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== -language-subtag-registry@~0.3.2: - version "0.3.20" - resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.20.tgz#a00a37121894f224f763268e431c55556b0c0755" - integrity sha512-KPMwROklF4tEx283Xw0pNKtfTj1gZ4UByp4EsIFWLgBavJltF4TiYPc39k06zSTsLzxTVXXDSpbwaQXaFB4Qeg== - -language-tags@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/language-tags/-/language-tags-1.0.5.tgz#d321dbc4da30ba8bf3024e040fa5c14661f9193a" - integrity sha1-0yHbxNowuovzAk4ED6XBRmH5GTo= - dependencies: - language-subtag-registry "~0.3.2" - leven@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== -levenary@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/levenary/-/levenary-1.1.1.tgz#842a9ee98d2075aa7faeedbe32679e9205f46f77" - integrity sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ== - dependencies: - leven "^3.1.0" - -levn@^0.3.0, levn@~0.3.0: +levn@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= @@ -4637,9 +3570,9 @@ lines-and-columns@^1.1.6: integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== lint-staged@^12.2.1: - version "12.2.1" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-12.2.1.tgz#e37b5a81deaabf5823f43b3aa903a70c15c9d0b3" - integrity sha512-VCVcA9C2Vt5HHxSR4EZVZFJcQRJH984CGBeY+cJ/xed4mBd+JidbM/xbKcCq5ASaygAV0iITtdsCTnID7h/1OQ== + version "12.2.2" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-12.2.2.tgz#e03d93b41092316e0f38b37c9630da807aae3cca" + integrity sha512-bcHEoM1M/f+K1BYdHcEuIn8K+zMOSJR3mkny6PAuQiTgcSUcRbUWaUD6porAYypxF4k1vYZZ2HutZt1p94Z1jQ== dependencies: cli-truncate "^3.1.0" colorette "^2.0.16" @@ -4669,23 +3602,24 @@ listr2@^3.13.5: through "^2.3.8" wrap-ansi "^7.0.0" -load-json-file@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" - integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= +load-json-file@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" + integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs= dependencies: graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" + parse-json "^4.0.0" + pify "^3.0.0" strip-bom "^3.0.0" -locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= +loader-utils@1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7" + integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA== dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" + big.js "^5.2.2" + emojis-list "^2.0.0" + json5 "^1.0.1" locate-path@^5.0.0: version "5.0.0" @@ -4701,52 +3635,11 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" -lodash.debounce@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" - integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= - -lodash.memoize@4.x: - version "4.1.2" - resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" - integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= - -lodash.merge@^4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" - integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== - -lodash.sortby@^4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" - integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= - -lodash@^4.17.14: - version "4.17.20" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" - integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== - -lodash@^4.17.15, lodash@^4.17.19: +lodash@^4.17.15, lodash@^4.7.0: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== -log-symbols@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-3.0.0.tgz#f3a08516a5dea893336a7dee14d18a1cfdab77c4" - integrity sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ== - dependencies: - chalk "^2.4.2" - -log-update@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/log-update/-/log-update-2.3.0.tgz#88328fd7d1ce7938b29283746f0b1bc126b24708" - integrity sha1-iDKP19HOeTiykoN0bwsbwSayRwg= - dependencies: - ansi-escapes "^3.0.0" - cli-cursor "^2.0.0" - wrap-ansi "^3.0.1" - log-update@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1" @@ -4757,27 +3650,13 @@ log-update@^4.0.0: slice-ansi "^4.0.0" wrap-ansi "^6.2.0" -lolex@^5.0.0: - version "5.1.2" - resolved "https://registry.yarnpkg.com/lolex/-/lolex-5.1.2.tgz#953694d098ce7c07bc5ed6d0e42bc6c0c6d5a367" - integrity sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A== - dependencies: - "@sinonjs/commons" "^1.7.0" - -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: +loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== dependencies: js-tokens "^3.0.0 || ^4.0.0" -lower-case@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.1.tgz#39eeb36e396115cc05e29422eaea9e692c9408c7" - integrity sha512-LiWgfDLLb1dwbFQZsSglpRj+1ctGnayXz3Uv0/WO8n558JycT5fg6zkNcnW0G68Nn0aEldTFeEfmjCfmqry/rQ== - dependencies: - tslib "^1.10.0" - lru-cache@^4.1.5: version "4.1.5" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" @@ -4786,36 +3665,38 @@ lru-cache@^4.1.5: pseudomap "^1.0.2" yallist "^2.1.2" +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + lz-string@^1.4.4: version "1.4.4" resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.4.4.tgz#c0d8eaf36059f705796e1e344811cf4c498d3a26" integrity sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY= -magic-string@^0.25.2, magic-string@^0.25.5: +magic-string@^0.25.7: version "0.25.7" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051" integrity sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA== dependencies: sourcemap-codec "^1.4.4" -make-dir@^3.0.0, make-dir@^3.0.2: +make-dir@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== dependencies: semver "^6.0.0" -make-error@1.x: - version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" - integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== - -makeerror@1.0.x: - version "1.0.11" - resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" - integrity sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw= +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== dependencies: - tmpl "1.0.x" + tmpl "1.0.5" map-cache@^0.2.2: version "0.2.2" @@ -4829,19 +3710,16 @@ map-visit@^1.0.0: dependencies: object-visit "^1.0.0" +memorystream@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" + integrity sha1-htcJCzDORV1j+64S3aUaR93K+bI= + merge-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== -micromatch@4.x: - version "4.0.2" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" - integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q== - dependencies: - braces "^3.0.1" - picomatch "^2.0.5" - micromatch@^3.1.4: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" @@ -4869,22 +3747,17 @@ micromatch@^4.0.2, micromatch@^4.0.4: braces "^3.0.1" picomatch "^2.2.3" -mime-db@1.44.0: - version "1.44.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" - integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== +mime-db@1.51.0: + version "1.51.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.51.0.tgz#d9ff62451859b18342d960850dc3cfb77e63fb0c" + integrity sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g== -mime-types@^2.1.12, mime-types@~2.1.19: - version "2.1.27" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" - integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w== +mime-types@^2.1.12: + version "2.1.34" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.34.tgz#5a712f9ec1503511a945803640fafe09d3793c24" + integrity sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A== dependencies: - mime-db "1.44.0" - -mimic-fn@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" - integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== + mime-db "1.51.0" mimic-fn@^2.1.0: version "2.1.0" @@ -4916,32 +3789,20 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp@0.x, mkdirp@^0.5.1: - version "0.5.5" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" - integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== - dependencies: - minimist "^1.2.5" - -mri@^1.1.0: - version "1.1.6" - resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.6.tgz#49952e1044db21dbf90f6cd92bc9c9a777d415a6" - integrity sha512-oi1b3MfbyGa7FJMP9GmLTttni5JoICpYBRlq+x5V16fZbLsnL9N3wFqqIm/nIG43FjUFkFh9Epzp/kzUGUnJxQ== - ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= -ms@2.1.2, ms@^2.1.1: +ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -mute-stream@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" - integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== +nanoid@^3.1.23, nanoid@^3.1.30: + version "3.2.0" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.2.0.tgz#62667522da6673971cca916a6d3eff3f415ff80c" + integrity sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA== nanomatch@^1.2.9: version "1.2.13" @@ -4965,44 +3826,66 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= +next@^12.0.8: + version "12.0.8" + resolved "https://registry.yarnpkg.com/next/-/next-12.0.8.tgz#29138f7cdd045e4bbba466af45bf430e769634b4" + integrity sha512-g5c1Kuh1F8tSXJn2rVvzYBzqe9EXaR6+rY3/KrQ7y0D9FueRLfHI35wM0DRadDcPSc3+vncspfhYH3jnYE/KjA== + dependencies: + "@next/env" "12.0.8" + "@next/react-refresh-utils" "12.0.8" + caniuse-lite "^1.0.30001283" + jest-worker "27.0.0-next.5" + node-fetch "2.6.1" + postcss "8.2.15" + react-is "17.0.2" + react-refresh "0.8.3" + stream-browserify "3.0.0" + styled-jsx "5.0.0-beta.6" + use-subscription "1.5.1" + optionalDependencies: + "@next/swc-android-arm64" "12.0.8" + "@next/swc-darwin-arm64" "12.0.8" + "@next/swc-darwin-x64" "12.0.8" + "@next/swc-linux-arm-gnueabihf" "12.0.8" + "@next/swc-linux-arm64-gnu" "12.0.8" + "@next/swc-linux-arm64-musl" "12.0.8" + "@next/swc-linux-x64-gnu" "12.0.8" + "@next/swc-linux-x64-musl" "12.0.8" + "@next/swc-win32-arm64-msvc" "12.0.8" + "@next/swc-win32-ia32-msvc" "12.0.8" + "@next/swc-win32-x64-msvc" "12.0.8" + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== -no-case@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.3.tgz#c21b434c1ffe48b39087e86cfb4d2582e9df18f8" - integrity sha512-ehY/mVQCf9BL0gKfsJBvFJen+1V//U+0HQMPrWct40ixE4jnv0bfvxDbWtAHL9EcaPEOJHVVYKoQn1TlZUB8Tw== - dependencies: - lower-case "^2.0.1" - tslib "^1.10.0" +node-fetch@2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" + integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= -node-modules-regexp@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" - integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= - -node-notifier@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-6.0.0.tgz#cea319e06baa16deec8ce5cd7f133c4a46b68e12" - integrity sha512-SVfQ/wMw+DesunOm5cKqr6yDcvUTDl/yc97ybGHMrteNEY6oekXpNpS3lZwgLlwz0FLgHoiW28ZpmBHUDg37cw== +node-notifier@^8.0.0: + version "8.0.2" + resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-8.0.2.tgz#f3167a38ef0d2c8a866a83e318c1ba0efeb702c5" + integrity sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg== dependencies: growly "^1.3.0" - is-wsl "^2.1.1" - semver "^6.3.0" + is-wsl "^2.2.0" + semver "^7.3.2" shellwords "^0.1.1" - which "^1.3.1" + uuid "^8.3.0" + which "^2.0.2" -node-releases@^1.1.61: - version "1.1.61" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.61.tgz#707b0fca9ce4e11783612ba4a2fcba09047af16e" - integrity sha512-DD5vebQLg8jLCOzwupn954fbIiZht05DAZs0k2u8NStSe6h9XdsuIQL8hSRKYiU8WUQRznmSDrKGbv3ObOmC7g== +node-releases@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.1.tgz#3d1d395f204f1f2f29a54358b9fb678765ad2fc5" + integrity sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA== nopt@^5.0.0: version "5.0.0" @@ -5033,6 +3916,21 @@ normalize-path@^3.0.0: resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== +npm-run-all@^4.1.5: + version "4.1.5" + resolved "https://registry.yarnpkg.com/npm-run-all/-/npm-run-all-4.1.5.tgz#04476202a15ee0e2e214080861bff12a51d98fba" + integrity sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ== + dependencies: + ansi-styles "^3.2.1" + chalk "^2.4.1" + cross-spawn "^6.0.5" + memorystream "^0.3.1" + minimatch "^3.0.4" + pidtree "^0.3.0" + read-pkg "^3.0.0" + shell-quote "^1.6.1" + string.prototype.padend "^3.0.0" + npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" @@ -5052,11 +3950,6 @@ nwsapi@^2.2.0: resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== -oauth-sign@~0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" - integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== - object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -5071,16 +3964,11 @@ object-copy@^0.1.0: define-property "^0.2.5" kind-of "^3.0.3" -object-inspect@^1.11.1: +object-inspect@^1.11.0, object-inspect@^1.11.1, object-inspect@^1.9.0: version "1.12.0" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0" integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g== -object-inspect@^1.7.0, object-inspect@^1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.8.0.tgz#df807e5ecf53a609cc6bfe93eac3cc7be5b3a9d0" - integrity sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA== - object-keys@^1.0.12, object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" @@ -5093,35 +3981,16 @@ object-visit@^1.0.0: dependencies: isobject "^3.0.0" -object.assign@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.1.tgz#303867a666cdd41936ecdedfb1f8f3e32a478cdd" - integrity sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA== +object.assign@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" + integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== dependencies: + call-bind "^1.0.0" define-properties "^1.1.3" - es-abstract "^1.18.0-next.0" has-symbols "^1.0.1" object-keys "^1.1.1" -object.entries@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.2.tgz#bc73f00acb6b6bb16c203434b10f9a7e797d3add" - integrity sha512-BQdB9qKmb/HyNdMNWVr7O3+z5MUIx3aiegEIJqjMBbBf0YT9RRxTJSim4mzFqtyr7PDAHigq0N9dO0m0tRakQA== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.5" - has "^1.0.3" - -object.fromentries@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.2.tgz#4a09c9b9bb3843dd0f89acdb517a794d4f355ac9" - integrity sha512-r3ZiBH7MQppDJVLx6fhD618GKNG40CZYH9wgwdhKxBDDbQgjeWGGd4AtkZad84d291YxvWe7bJGuE65Anh0dxQ== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" - function-bind "^1.1.1" - has "^1.0.3" - object.pick@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" @@ -5129,16 +3998,6 @@ object.pick@^1.3.0: dependencies: isobject "^3.0.1" -object.values@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.1.tgz#68a99ecde356b7e9295a3c5e0ce31dc8c953de5e" - integrity sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" - function-bind "^1.1.1" - has "^1.0.3" - once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -5146,13 +4005,6 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" -onetime@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" - integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= - dependencies: - mimic-fn "^1.0.0" - onetime@^5.1.0, onetime@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" @@ -5165,7 +4017,7 @@ opencollective-postinstall@^2.0.2: resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259" integrity sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q== -optionator@^0.8.1, optionator@^0.8.3: +optionator@^0.8.1: version "0.8.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== @@ -5177,47 +4029,16 @@ optionator@^0.8.1, optionator@^0.8.3: type-check "~0.3.2" word-wrap "~1.2.3" -ora@^4.0.3: - version "4.1.1" - resolved "https://registry.yarnpkg.com/ora/-/ora-4.1.1.tgz#566cc0348a15c36f5f0e979612842e02ba9dddbc" - integrity sha512-sjYP8QyVWBpBZWD6Vr1M/KwknSw6kJOz41tvGMlwWeClHBtYKTbHMki1PsLZnxKpXMPbTKv9b3pjQu3REib96A== - dependencies: - chalk "^3.0.0" - cli-cursor "^3.1.0" - cli-spinners "^2.2.0" - is-interactive "^1.0.0" - log-symbols "^3.0.0" - mute-stream "0.0.8" - strip-ansi "^6.0.0" - wcwidth "^1.0.1" - -os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= - p-each-series@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-2.1.0.tgz#961c8dd3f195ea96c747e636b262b800a6b1af48" - integrity sha512-ZuRs1miPT4HrjFa+9fRfOFXxGJfORgelKV9f9nNOWw2gl6gVsRaVDOQP0+MI0G0wGKns1Yacsu0GjOFbTK0JFQ== + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-2.2.0.tgz#105ab0357ce72b202a8a8b94933672657b5e2a9a" + integrity sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA== p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= -p-finally@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-2.0.1.tgz#bd6fcaa9c559a096b680806f4d657b3f0f240561" - integrity sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw== - -p-limit@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== - dependencies: - p-try "^1.0.0" - p-limit@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" @@ -5232,13 +4053,6 @@ p-limit@^3.0.2: dependencies: yocto-queue "^0.1.0" -p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= - dependencies: - p-limit "^1.1.0" - p-locate@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" @@ -5260,11 +4074,6 @@ p-map@^4.0.0: dependencies: aggregate-error "^3.0.0" -p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= - p-try@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" @@ -5277,12 +4086,13 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" -parse-json@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" - integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= +parse-json@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= dependencies: - error-ex "^1.2.0" + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" parse-json@^5.0.0: version "5.2.0" @@ -5294,29 +4104,16 @@ parse-json@^5.0.0: json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" -parse5@5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.0.tgz#c59341c9723f414c452975564c7c00a68d58acd2" - integrity sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ== - -pascal-case@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.1.tgz#5ac1975133ed619281e88920973d2cd1f279de5f" - integrity sha512-XIeHKqIrsquVTQL2crjq3NfJUxmdLasn3TYOU0VBM+UX2a6ztAWBlJQBePLGY7VHW8+2dRadeIPK5+KImwTxQA== - dependencies: - no-case "^3.0.3" - tslib "^1.10.0" +parse5@6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" + integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== pascalcase@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= - path-exists@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" @@ -5337,58 +4134,49 @@ path-key@^3.0.0, path-key@^3.1.0: resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== -path-parse@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" - integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-type@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" - integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= +path-type@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" + integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== dependencies: - pify "^2.0.0" + pify "^3.0.0" path-type@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= - -picomatch@^2.0.4, picomatch@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" - integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== -picomatch@^2.0.5, picomatch@^2.2.3: +picomatch@^2.0.4, picomatch@^2.2.3: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== -pify@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= +pidtree@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.3.1.tgz#ef09ac2cc0533df1f3250ccf2c4d366b0d12114a" + integrity sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA== -pirates@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" - integrity sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA== - dependencies: - node-modules-regexp "^1.0.0" +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= -pkg-dir@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" - integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= - dependencies: - find-up "^2.1.0" +pirates@^4.0.1: + version "4.0.4" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.4.tgz#07df81e61028e402735cdd49db701e4885b4e6e6" + integrity sha512-ZIrVPH+A52Dw84R0L3/VS9Op04PuQ2SEoJL6bkshmiTic/HldyW9Tf7oH5mhJZBK7NmDx27vSMrYEXPXclpDKw== -pkg-dir@^4.1.0, pkg-dir@^4.2.0: +pkg-dir@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== @@ -5409,54 +4197,55 @@ please-upgrade-node@^3.2.0: dependencies: semver-compare "^1.0.0" -pn@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb" - integrity sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA== +popmotion@11.0.3: + version "11.0.3" + resolved "https://registry.yarnpkg.com/popmotion/-/popmotion-11.0.3.tgz#565c5f6590bbcddab7a33a074bb2ba97e24b0cc9" + integrity sha512-Y55FLdj3UxkR7Vl3s7Qr4e9m0onSnP8W7d/xQLsoJM40vs6UKHFdygs6SWryasTZYqugMjm3BepCF4CWXDiHgA== + dependencies: + framesync "6.0.1" + hey-listen "^1.0.8" + style-value-types "5.0.0" + tslib "^2.1.0" posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= +postcss@8.2.15: + version "8.2.15" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.2.15.tgz#9e66ccf07292817d226fc315cbbf9bc148fbca65" + integrity sha512-2zO3b26eJD/8rb106Qu2o7Qgg52ND5HPjcyQiK2B98O388h43A448LCslC0dI2P97wCAQRJsFvwTRcXxTKds+Q== + dependencies: + colorette "^1.2.2" + nanoid "^3.1.23" + source-map "^0.6.1" + +postcss@^8.1.10, postcss@^8.4.5: + version "8.4.5" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.5.tgz#bae665764dfd4c6fcc24dc0fdf7e7aa00cc77f95" + integrity sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg== + dependencies: + nanoid "^3.1.30" + picocolors "^1.0.0" + source-map-js "^1.0.1" + prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= -prettier-linter-helpers@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" - integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== - dependencies: - fast-diff "^1.1.2" - -prettier@^1.19.1: - version "1.19.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" - integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== - -pretty-format@^25.2.1, pretty-format@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-25.5.0.tgz#7873c1d774f682c34b8d48b6743a2bf2ac55791a" - integrity sha512-kbo/kq2LQ/A/is0PQwsEHM7Ca6//bGPPvU6UnsdDRSKTWxT/ru/xb88v4BJf6a69H+uTytOEsTusT9ksd/1iWQ== - dependencies: - "@jest/types" "^25.5.0" - ansi-regex "^5.0.0" - ansi-styles "^4.0.0" - react-is "^16.12.0" +prettier-plugin-tailwindcss@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.1.4.tgz#b09e826a57a0f69b0662eededd659b3d5a5551e7" + integrity sha512-kt3YFWqxcG9+bilBI0hPF7RjQZNtgBRvjJZGw6B2MNAjPqlfcYIiZnNaIEnq4XimKLTzZYxz6jQnUXmSQ/5njg== -pretty-format@^26.1.0: - version "26.4.2" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.4.2.tgz#d081d032b398e801e2012af2df1214ef75a81237" - integrity sha512-zK6Gd8zDsEiVydOCGLkoBoZuqv8VTiHyAbKznXe/gaph/DAeZOmit9yMfgIz5adIgAMMs5XfoYSwAX3jcCO1tA== - dependencies: - "@jest/types" "^26.3.0" - ansi-regex "^5.0.0" - ansi-styles "^4.0.0" - react-is "^16.12.0" +prettier@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a" + integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg== -pretty-format@^26.4.2, pretty-format@^26.6.2: +pretty-format@^26.1.0, pretty-format@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93" integrity sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg== @@ -5484,37 +4273,22 @@ pretty@^2.0.0: extend-shallow "^2.0.1" js-beautify "^1.6.12" -progress-estimator@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/progress-estimator/-/progress-estimator-0.2.2.tgz#1c3947a5782ea56e40c8fccc290ac7ceeb1b91cb" - integrity sha512-GF76Ac02MTJD6o2nMNtmtOFjwWCnHcvXyn5HOWPQnEMO8OTLw7LAvNmrwe8LmdsB+eZhwUu9fX/c9iQnBxWaFA== - dependencies: - chalk "^2.4.1" - cli-spinners "^1.3.1" - humanize-duration "^3.15.3" - log-update "^2.3.0" - -progress@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - prompts@^2.0.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.3.2.tgz#480572d89ecf39566d2bd3fe2c9fccb7c4c0b068" - integrity sha512-Q06uKs2CkNYVID0VqwfAl9mipo99zkBv/n2JtWY89Yxa3ZabWSrs0e2KTudKVa3peLUvYXMefDqIleLPVUBZMA== + version "2.4.2" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== dependencies: kleur "^3.0.3" - sisteransi "^1.0.4" + sisteransi "^1.0.5" -prop-types@^15.6.2, prop-types@^15.7.2: - version "15.7.2" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" - integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== +prop-types@^15.6.2: + version "15.8.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== dependencies: loose-envify "^1.4.0" object-assign "^4.1.1" - react-is "^16.8.1" + react-is "^16.13.1" proto-list@~1.2.1: version "1.2.4" @@ -5526,7 +4300,7 @@ pseudomap@^1.0.2: resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= -psl@^1.1.28: +psl@^1.1.33: version "1.8.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== @@ -5539,24 +4313,12 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" -punycode@^2.1.0, punycode@^2.1.1: +punycode@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== -qs@~6.5.2: - version "6.5.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" - integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== - -randombytes@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" - integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== - dependencies: - safe-buffer "^5.1.0" - -react-dom@^16.14.0: +react-dom@16.14.0, react-dom@^16.14.0: version "16.14.0" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.14.0.tgz#7ad838ec29a777fb3c75c3a190f661cf92ab8b89" integrity sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw== @@ -5566,17 +4328,22 @@ react-dom@^16.14.0: prop-types "^15.6.2" scheduler "^0.19.1" -react-is@^16.12.0, react-is@^16.8.1: +react-is@17.0.2, react-is@^17.0.1: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== + +react-is@^16.13.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== -react-is@^17.0.1: - version "17.0.2" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" - integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== +react-refresh@0.8.3: + version "0.8.3" + resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.8.3.tgz#721d4657672d400c5e3c75d063c4a85fb2d5d68f" + integrity sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg== -react@^16.14.0: +react@16.14.0, react@^16.14.0: version "16.14.0" resolved "https://registry.yarnpkg.com/react/-/react-16.14.0.tgz#94d776ddd0aaa37da3eda8fc5b6b18a4c9a3114d" integrity sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g== @@ -5585,14 +4352,6 @@ react@^16.14.0: object-assign "^4.1.1" prop-types "^15.6.2" -read-pkg-up@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" - integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= - dependencies: - find-up "^2.0.0" - read-pkg "^2.0.0" - read-pkg-up@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" @@ -5602,14 +4361,14 @@ read-pkg-up@^7.0.1: read-pkg "^5.2.0" type-fest "^0.8.1" -read-pkg@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" - integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= +read-pkg@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" + integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k= dependencies: - load-json-file "^2.0.0" + load-json-file "^4.0.0" normalize-package-data "^2.3.2" - path-type "^2.0.0" + path-type "^3.0.0" read-pkg@^5.2.0: version "5.2.0" @@ -5621,17 +4380,14 @@ read-pkg@^5.2.0: parse-json "^5.0.0" type-fest "^0.6.0" -realpath-native@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-2.0.0.tgz#7377ac429b6e1fd599dc38d08ed942d0d7beb866" - integrity sha512-v1SEYUOXXdbBZK8ZuNgO4TBjamPsiSgcFr0aP+tEKpQZK8vooEUqV6nm6Cv502mX4NF2EfsnVqtNAHG+/6Ur1Q== - -rechoir@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" - integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= +readable-stream@^3.5.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== dependencies: - resolve "^1.1.6" + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" redent@^3.0.0: version "3.0.0" @@ -5641,35 +4397,11 @@ redent@^3.0.0: indent-string "^4.0.0" strip-indent "^3.0.0" -regenerate-unicode-properties@^8.2.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec" - integrity sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA== - dependencies: - regenerate "^1.4.0" - -regenerate@^1.4.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.1.tgz#cad92ad8e6b591773485fbe05a485caf4f457e6f" - integrity sha512-j2+C8+NtXQgEKWk49MMP5P/u2GhnahTtVkRIHr5R5lVRlbKvmQ+oS+A5aLKWp2ma5VkT8sh6v+v4hbH0YHR66A== - regenerator-runtime@^0.13.4: version "0.13.9" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== -regenerator-runtime@^0.13.7: - version "0.13.7" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" - integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew== - -regenerator-transform@^0.14.2: - version "0.14.5" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4" - integrity sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw== - dependencies: - "@babel/runtime" "^7.8.4" - regex-not@^1.0.0, regex-not@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" @@ -5678,105 +4410,21 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" -regexp.prototype.flags@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz#7aba89b3c13a64509dabcf3ca8d9fbb9bdf5cb75" - integrity sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" - -regexpp@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" - integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== - -regexpp@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2" - integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q== - -regexpu-core@^4.7.0: - version "4.7.1" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.1.tgz#2dea5a9a07233298fbf0db91fa9abc4c6e0f8ad6" - integrity sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ== - dependencies: - regenerate "^1.4.0" - regenerate-unicode-properties "^8.2.0" - regjsgen "^0.5.1" - regjsparser "^0.6.4" - unicode-match-property-ecmascript "^1.0.4" - unicode-match-property-value-ecmascript "^1.2.0" - -regjsgen@^0.5.1: - version "0.5.2" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.2.tgz#92ff295fb1deecbf6ecdab2543d207e91aa33733" - integrity sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A== - -regjsparser@^0.6.4: - version "0.6.4" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.4.tgz#a769f8684308401a66e9b529d2436ff4d0666272" - integrity sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw== - dependencies: - jsesc "~0.5.0" - remove-trailing-separator@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= repeat-element@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" - integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== + version "1.1.4" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" + integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== repeat-string@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= -request-promise-core@1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.4.tgz#3eedd4223208d419867b78ce815167d10593a22f" - integrity sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw== - dependencies: - lodash "^4.17.19" - -request-promise-native@^1.0.7: - version "1.0.9" - resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.9.tgz#e407120526a5efdc9a39b28a5679bf47b9d9dc28" - integrity sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g== - dependencies: - request-promise-core "1.1.4" - stealthy-require "^1.1.1" - tough-cookie "^2.3.3" - -request@^2.88.0: - version "2.88.2" - resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" - integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.8.0" - caseless "~0.12.0" - combined-stream "~1.0.6" - extend "~3.0.2" - forever-agent "~0.6.1" - form-data "~2.3.2" - har-validator "~5.1.3" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.19" - oauth-sign "~0.9.0" - performance-now "^2.1.0" - qs "~6.5.2" - safe-buffer "^5.1.2" - tough-cookie "~2.5.0" - tunnel-agent "^0.6.0" - uuid "^3.3.2" - require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -5809,25 +4457,23 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" - integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= - -resolve@1.17.0, resolve@^1.1.6, resolve@^1.10.0, resolve@^1.11.0, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.14.2, resolve@^1.17.0, resolve@^1.3.2: - version "1.17.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" - integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== +resolve@^1.10.0, resolve@^1.18.1: + version "1.21.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.21.0.tgz#b51adc97f3472e6a5cf4444d34bc9d6b9037591f" + integrity sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA== dependencies: - path-parse "^1.0.6" + is-core-module "^2.8.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" -restore-cursor@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" - integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= +resolve@^1.20.0: + version "1.21.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.21.1.tgz#1a88c73f5ca8ab0aabc8b888c4170de26c92c4cc" + integrity sha512-lfEImVbnolPuaSZuLQ52cAxPBHeI77sPwCOWRdy12UG/CNa8an7oBHH1R+Fp1/mUqSJi4c8TIP6FOIPSZAUrEQ== dependencies: - onetime "^2.0.0" - signal-exit "^3.0.2" + is-core-module "^2.8.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" restore-cursor@^3.1.0: version "3.1.0" @@ -5847,83 +4493,25 @@ rfdc@^1.3.0: resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== -rimraf@2.6.3: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== - dependencies: - glob "^7.1.3" - -rimraf@^3.0.0: +rimraf@^3.0.0, rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== dependencies: glob "^7.1.3" -rollup-plugin-sourcemaps@^0.6.2: - version "0.6.3" - resolved "https://registry.yarnpkg.com/rollup-plugin-sourcemaps/-/rollup-plugin-sourcemaps-0.6.3.tgz#bf93913ffe056e414419607f1d02780d7ece84ed" - integrity sha512-paFu+nT1xvuO1tPFYXGe+XnQvg4Hjqv/eIhG8i5EspfYYPBKL57X7iVbfv55aNVASg3dzWvES9dmWsL2KhfByw== - dependencies: - "@rollup/pluginutils" "^3.0.9" - source-map-resolve "^0.6.0" - -rollup-plugin-terser@^5.1.2: - version "5.3.1" - resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-5.3.1.tgz#8c650062c22a8426c64268548957463bf981b413" - integrity sha512-1pkwkervMJQGFYvM9nscrUoncPwiKR/K+bHdjv6PFgRo3cgPHoRT83y2Aa3GvINj4539S15t/tpFPb775TDs6w== - dependencies: - "@babel/code-frame" "^7.5.5" - jest-worker "^24.9.0" - rollup-pluginutils "^2.8.2" - serialize-javascript "^4.0.0" - terser "^4.6.2" - -rollup-plugin-typescript2@^0.27.3: - version "0.27.3" - resolved "https://registry.yarnpkg.com/rollup-plugin-typescript2/-/rollup-plugin-typescript2-0.27.3.tgz#cd9455ac026d325b20c5728d2cc54a08a771b68b" - integrity sha512-gmYPIFmALj9D3Ga1ZbTZAKTXq1JKlTQBtj299DXhqYz9cL3g/AQfUvbb2UhH+Nf++cCq941W2Mv7UcrcgLzJJg== - dependencies: - "@rollup/pluginutils" "^3.1.0" - find-cache-dir "^3.3.1" - fs-extra "8.1.0" - resolve "1.17.0" - tslib "2.0.1" - -rollup-pluginutils@^2.8.2: - version "2.8.2" - resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz#72f2af0748b592364dbd3389e600e5a9444a351e" - integrity sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ== - dependencies: - estree-walker "^0.6.1" - -rollup@^1.32.1: - version "1.32.1" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.32.1.tgz#4480e52d9d9e2ae4b46ba0d9ddeaf3163940f9c4" - integrity sha512-/2HA0Ec70TvQnXdzynFffkjA6XN+1e2pEv/uKS5Ulca40g2L7KuOE3riasHoNVHOsFD5KKZgDsMk1CP3Tw9s+A== - dependencies: - "@types/estree" "*" - "@types/node" "*" - acorn "^7.1.0" +rollup@^2.59.0: + version "2.65.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.65.0.tgz#936ed140ac28f87aff22c6ac950b3d0303fadc3b" + integrity sha512-ohZVYrhtVMTqqeqH26sngfMiyGDg6gCUReOsoflXvYpzUkDHp8sVG8F9FQxjs72OfnLWpXP2nNNqQ9I0vkRovA== + optionalDependencies: + fsevents "~2.3.2" rsvp@^4.8.4: version "4.8.5" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== -run-async@^2.4.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" - integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== - -rxjs@^6.6.0: - version "6.6.3" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.3.tgz#8ca84635c4daa900c0d3967a6ee7ac60271ee552" - integrity sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ== - dependencies: - tslib "^1.9.0" - rxjs@^7.5.1: version "7.5.2" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.2.tgz#11e4a3a1dfad85dbf7fb6e33cbba17668497490b" @@ -5931,23 +4519,16 @@ rxjs@^7.5.1: dependencies: tslib "^2.1.0" -sade@^1.4.2: - version "1.7.3" - resolved "https://registry.yarnpkg.com/sade/-/sade-1.7.3.tgz#a217ccc4fb4abb2d271648bf48f6628b2636fa1b" - integrity sha512-m4BctppMvJ60W1dXnHq7jMmFe3hPJZDAH85kQ3ACTo7XZNVUuTItCQ+2HfyaMeV5cKrbw7l4vD/6We3GBxvdJw== - dependencies: - mri "^1.1.0" - -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== +safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + safe-regex@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" @@ -5955,7 +4536,7 @@ safe-regex@^1.1.0: dependencies: ret "~0.1.10" -"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: +"safer-buffer@>= 2.1.2 < 3": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -5975,12 +4556,12 @@ sane@^4.0.3: minimist "^1.1.1" walker "~1.0.5" -saxes@^3.1.9: - version "3.1.11" - resolved "https://registry.yarnpkg.com/saxes/-/saxes-3.1.11.tgz#d59d1fd332ec92ad98a2e0b2ee644702384b1c5b" - integrity sha512-Ydydq3zC+WYDJK1+gRxRapLIED9PWeSuuS41wqyoRmzvhhh9nc+QQrVMKJYzJFULazeGhzSV0QleN2wD3boh2g== +saxes@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" + integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== dependencies: - xmlchars "^2.1.1" + xmlchars "^2.2.0" scheduler@^0.19.1: version "0.19.1" @@ -6000,32 +4581,22 @@ semver-regex@^3.1.2: resolved "https://registry.yarnpkg.com/semver-regex/-/semver-regex-3.1.3.tgz#b2bcc6f97f63269f286994e297e229b6245d0dc3" integrity sha512-Aqi54Mk9uYTjVexLnR67rTyBusmwd04cLkHy9hNvk3+G3nT2Oyg7E0l4XVbOaNwIvQ3hHeYxGcyEy+mKreyBFQ== -"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.6.0: +"semver@2 || 3 || 4 || 5", semver@^5.5.0, semver@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@6.x, semver@^6.0.0, semver@^6.1.2, semver@^6.3.0: +semver@^6.0.0, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" - integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== - -semver@^7.1.1, semver@^7.3.2: - version "7.3.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" - integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== - -serialize-javascript@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa" - integrity sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw== +semver@^7.3.2: + version "7.3.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== dependencies: - randombytes "^2.1.0" + lru-cache "^6.0.0" set-blocking@^2.0.0: version "2.0.0" @@ -6066,44 +4637,36 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -shelljs@^0.8.3: - version "0.8.4" - resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.4.tgz#de7684feeb767f8716b326078a8a00875890e3c2" - integrity sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ== - dependencies: - glob "^7.0.0" - interpret "^1.0.0" - rechoir "^0.6.2" +shell-quote@^1.6.1: + version "1.7.3" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.3.tgz#aa40edac170445b9a431e17bb62c0b881b9c4123" + integrity sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw== shellwords@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== -side-channel@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.3.tgz#cdc46b057550bbab63706210838df5d4c19519c3" - integrity sha512-A6+ByhlLkksFoUepsGxfj5x1gTSrs+OydsRptUxeNCabQpCFUvcwIczgOigI8vhY/OJCnPnyE9rGiwgvr9cS1g== +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== dependencies: - es-abstract "^1.18.0-next.0" - object-inspect "^1.8.0" + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" sigmund@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" integrity sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA= -signal-exit@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" - integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== - -signal-exit@^3.0.2, signal-exit@^3.0.3: +signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: version "3.0.6" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.6.tgz#24e630c4b0f03fea446a2bd299e62b4a6ca8d0af" integrity sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ== -sisteransi@^1.0.4: +sisteransi@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== @@ -6113,15 +4676,6 @@ slash@^3.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== -slice-ansi@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" - integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== - dependencies: - ansi-styles "^3.2.0" - astral-regex "^1.0.0" - is-fullwidth-code-point "^2.0.0" - slice-ansi@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787" @@ -6187,6 +4741,11 @@ snapshot-diff@^0.8.1: jest-snapshot "^26.1.0" pretty-format "^26.1.0" +source-map-js@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + source-map-resolve@^0.5.0: version "0.5.3" resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" @@ -6206,18 +4765,23 @@ source-map-resolve@^0.6.0: atob "^2.1.2" decode-uri-component "^0.2.0" -source-map-support@^0.5.6, source-map-support@~0.5.12: - version "0.5.19" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" - integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== +source-map-support@^0.5.6: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== dependencies: buffer-from "^1.0.0" source-map "^0.6.0" source-map-url@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" - integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= + version "0.4.1" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" + integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== + +source-map@0.7.3, source-map@^0.7.3: + version "0.7.3" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" + integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== source-map@^0.5.0, source-map@^0.5.6: version "0.5.7" @@ -6229,11 +4793,6 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -source-map@^0.7.3: - version "0.7.3" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" - integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== - sourcemap-codec@^1.4.4: version "1.4.8" resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" @@ -6261,9 +4820,9 @@ spdx-expression-parse@^3.0.0: spdx-license-ids "^3.0.0" spdx-license-ids@^3.0.0: - version "3.0.6" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.6.tgz#c80757383c28abf7296744998cbc106ae8b854ce" - integrity sha512-+orQK83kyMva3WyPf59k1+Y525csj5JejicWut55zeTWANuN17qSiSLUXWtzHeNWORSvT7GLDJ/E/XiIWoXBTw== + version "3.0.11" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz#50c0d8c40a14ec1bf449bae69a0ea4685a9d9f95" + integrity sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g== split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" @@ -6277,30 +4836,10 @@ sprintf-js@~1.0.2: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= -sshpk@^1.7.0: - version "1.16.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" - integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - bcrypt-pbkdf "^1.0.0" - dashdash "^1.12.0" - ecc-jsbn "~0.1.1" - getpass "^0.1.1" - jsbn "~0.1.0" - safer-buffer "^2.0.2" - tweetnacl "~0.14.0" - -stack-utils@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.2.tgz#33eba3897788558bebfc2db059dc158ec36cebb8" - integrity sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA== - stack-utils@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.2.tgz#5cf48b4557becb4638d0bc4f21d23f5d19586593" - integrity sha512-0H7QK2ECz3fyZMzQ8rH0j2ykpfbnd20BFtfg/SqVC2+sCTtcw0aDTGB7dk+de4U4uUeuz6nOtJcrkFFLG1B0Rg== + version "2.0.5" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" + integrity sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA== dependencies: escape-string-regexp "^2.0.0" @@ -6312,40 +4851,31 @@ static-extend@^0.1.1: define-property "^0.2.5" object-copy "^0.1.0" -stealthy-require@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" - integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= +stream-browserify@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-3.0.0.tgz#22b0a2850cdf6503e73085da1fc7b7d0c2122f2f" + integrity sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA== + dependencies: + inherits "~2.0.4" + readable-stream "^3.5.0" string-argv@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" integrity sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg== -string-length@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/string-length/-/string-length-3.1.0.tgz#107ef8c23456e187a8abd4a61162ff4ac6e25837" - integrity sha512-Ttp5YvkGm5v9Ijagtaz1BnN+k9ObpvS0eIBblPMp2YWL8FBmi9qblQ9fexc2k/CXFgrTIteU3jAw3payCnwSTA== - dependencies: - astral-regex "^1.0.0" - strip-ansi "^5.2.0" - -string-width@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" +string-hash@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/string-hash/-/string-hash-1.1.3.tgz#e8aafc0ac1855b4666929ed7dd1275df5d6c811b" + integrity sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs= -string-width@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" - integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== dependencies: - emoji-regex "^7.0.1" - is-fullwidth-code-point "^2.0.0" - strip-ansi "^5.1.0" + char-regex "^1.0.2" + strip-ansi "^6.0.0" string-width@^4.1.0, string-width@^4.2.0: version "4.2.3" @@ -6365,47 +4895,37 @@ string-width@^5.0.0: emoji-regex "^9.2.2" strip-ansi "^7.0.1" -string.prototype.matchall@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.2.tgz#48bb510326fb9fdeb6a33ceaa81a6ea04ef7648e" - integrity sha512-N/jp6O5fMf9os0JU3E72Qhf590RSRZU/ungsL/qJUYVTNv7hTG0P/dbPjxINVN9jpscu3nzYwKESU3P3RY5tOg== +string.prototype.padend@^3.0.0: + version "3.1.3" + resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.1.3.tgz#997a6de12c92c7cb34dc8a201a6c53d9bd88a5f1" + integrity sha512-jNIIeokznm8SD/TZISQsZKYu7RJyheFNt84DUPrh482GC8RVp2MKqm2O5oBRdGxbDQoXrhhWtPIWQOiy20svUg== dependencies: + call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.17.0" - has-symbols "^1.0.1" - internal-slot "^1.0.2" - regexp.prototype.flags "^1.3.0" - side-channel "^1.0.2" + es-abstract "^1.19.1" -string.prototype.trimend@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913" - integrity sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g== +string.prototype.trimend@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" + integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== dependencies: + call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.17.5" -string.prototype.trimstart@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54" - integrity sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw== +string.prototype.trimstart@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" + integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== dependencies: + call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.17.5" - -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= - dependencies: - ansi-regex "^3.0.0" -strip-ansi@^5.1.0, strip-ansi@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" - integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== dependencies: - ansi-regex "^4.1.0" + safe-buffer "~5.2.0" strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" @@ -6448,10 +4968,37 @@ strip-indent@^3.0.0: dependencies: min-indent "^1.0.0" -strip-json-comments@^3.0.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== +style-value-types@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/style-value-types/-/style-value-types-5.0.0.tgz#76c35f0e579843d523187989da866729411fc8ad" + integrity sha512-08yq36Ikn4kx4YU6RD7jWEv27v4V+PUsOGa4n/as8Et3CuODMJQ00ENeAVXAeydX4Z2j1XHZF1K2sX4mGl18fA== + dependencies: + hey-listen "^1.0.8" + tslib "^2.1.0" + +styled-jsx@5.0.0-beta.6: + version "5.0.0-beta.6" + resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.0.0-beta.6.tgz#666552f8831a06f80c9084a47afc4b32b0c9f461" + integrity sha512-b1cM7Xyp2r1lsNpvoZ6wmTI8qxD0557vH2feHakNU8LMkzfJDgTQMul6O7sSYY0GxQ73pKEN69hCDp71w6Q0nA== + dependencies: + "@babel/plugin-syntax-jsx" "7.14.5" + "@babel/types" "7.15.0" + convert-source-map "1.7.0" + loader-utils "1.2.3" + source-map "0.7.3" + string-hash "1.1.3" + stylis "3.5.4" + stylis-rule-sheet "0.0.10" + +stylis-rule-sheet@0.0.10: + version "0.0.10" + resolved "https://registry.yarnpkg.com/stylis-rule-sheet/-/stylis-rule-sheet-0.0.10.tgz#44e64a2b076643f4b52e5ff71efc04d8c3c4a430" + integrity sha512-nTbZoaqoBnmK+ptANthb10ZRZOGC+EmTLLUxeYIuHNkEKcmKgXX1XWKkUBT2Ac4es3NybooPe0SmvKdhKJZAuw== + +stylis@3.5.4: + version "3.5.4" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.5.4.tgz#f665f25f5e299cf3d64654ab949a57c768b73fbe" + integrity sha512-8/3pSmthWM7lsPBKv7NXkzn2Uc9W7NotcwGNpJaa3k7WMM1XDCA4MgT5k/8BIexd5ydZdboXtU90XH9Ec4Bv/Q== supports-color@^5.3.0: version "5.5.0" @@ -6460,13 +5007,6 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" -supports-color@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" - integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== - dependencies: - has-flag "^3.0.0" - supports-color@^7.0.0, supports-color@^7.1.0: version "7.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" @@ -6474,34 +5014,36 @@ supports-color@^7.0.0, supports-color@^7.1.0: dependencies: has-flag "^4.0.0" +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + supports-color@^9.2.1: version "9.2.1" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-9.2.1.tgz#599dc9d45acf74c6176e0d880bab1d7d718fe891" integrity sha512-Obv7ycoCTG51N7y175StI9BlAXrmgZrFhZOb0/PyjHBher/NmsdBgbbQ1Inhq+gIhz6+7Gb+jWF2Vqi7Mf1xnQ== supports-hyperlinks@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz#f663df252af5f37c5d49bbd7eeefa9e0b9e59e47" - integrity sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA== + version "2.2.0" + resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb" + integrity sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ== dependencies: has-flag "^4.0.0" supports-color "^7.0.0" -symbol-tree@^3.2.2: +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +symbol-tree@^3.2.4: version "3.2.4" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== -table@^5.2.3: - version "5.4.6" - resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" - integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== - dependencies: - ajv "^6.10.2" - lodash "^4.17.14" - slice-ansi "^2.1.0" - string-width "^3.0.0" - terminal-link@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" @@ -6510,15 +5052,6 @@ terminal-link@^2.0.0: ansi-escapes "^4.2.1" supports-hyperlinks "^2.0.0" -terser@^4.6.2: - version "4.8.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17" - integrity sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw== - dependencies: - commander "^2.20.0" - source-map "~0.6.1" - source-map-support "~0.5.12" - test-exclude@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" @@ -6528,40 +5061,20 @@ test-exclude@^6.0.0: glob "^7.1.4" minimatch "^3.0.4" -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= - throat@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b" integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA== -through@^2.3.6, through@^2.3.8: +through@^2.3.8: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= -tiny-glob@^0.2.6: - version "0.2.6" - resolved "https://registry.yarnpkg.com/tiny-glob/-/tiny-glob-0.2.6.tgz#9e056e169d9788fe8a734dfa1ff02e9b92ed7eda" - integrity sha512-A7ewMqPu1B5PWwC3m7KVgAu96Ch5LA0w4SnEN/LbDREj/gAD0nPWboRbn8YoP9ISZXqeNAlMvKSKoEuhcfK3Pw== - dependencies: - globalyzer "^0.1.0" - globrex "^0.1.1" - -tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== - dependencies: - os-tmpdir "~1.0.2" - -tmpl@1.0.x: - version "1.0.4" - resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" - integrity sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE= +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== to-fast-properties@^2.0.0: version "2.0.0" @@ -6600,157 +5113,27 @@ to-regex@^3.0.1, to-regex@^3.0.2: regex-not "^1.0.2" safe-regex "^1.1.0" -tough-cookie@^2.3.3, tough-cookie@~2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" - integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== +tough-cookie@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" + integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg== dependencies: - psl "^1.1.28" + psl "^1.1.33" punycode "^2.1.1" + universalify "^0.1.2" -tough-cookie@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-3.0.1.tgz#9df4f57e739c26930a018184887f4adb7dca73b2" - integrity sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg== +tr46@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" + integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw== dependencies: - ip-regex "^2.1.0" - psl "^1.1.28" punycode "^2.1.1" -tr46@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" - integrity sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk= - dependencies: - punycode "^2.1.0" - -ts-jest@^25.3.1: - version "25.5.1" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-25.5.1.tgz#2913afd08f28385d54f2f4e828be4d261f4337c7" - integrity sha512-kHEUlZMK8fn8vkxDjwbHlxXRB9dHYpyzqKIGDNxbzs+Rz+ssNDSDNusEK8Fk/sDd4xE6iKoQLfFkFVaskmTJyw== - dependencies: - bs-logger "0.x" - buffer-from "1.x" - fast-json-stable-stringify "2.x" - json5 "2.x" - lodash.memoize "4.x" - make-error "1.x" - micromatch "4.x" - mkdirp "0.x" - semver "6.x" - yargs-parser "18.x" - -tsconfig-paths@^3.9.0: - version "3.9.0" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz#098547a6c4448807e8fcb8eae081064ee9a3c90b" - integrity sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw== - dependencies: - "@types/json5" "^0.0.29" - json5 "^1.0.1" - minimist "^1.2.0" - strip-bom "^3.0.0" - -tsdx@^0.14.1: - version "0.14.1" - resolved "https://registry.yarnpkg.com/tsdx/-/tsdx-0.14.1.tgz#8771d509b6fc523ad971bae3a63ebe3a88355ab3" - integrity sha512-keHmFdCL2kx5nYFlBdbE3639HQ2v9iGedAFAajobrUTH2wfX0nLPdDhbHv+GHLQZqf0c5ur1XteE8ek/+Eyj5w== - dependencies: - "@babel/core" "^7.4.4" - "@babel/helper-module-imports" "^7.0.0" - "@babel/parser" "^7.11.5" - "@babel/plugin-proposal-class-properties" "^7.4.4" - "@babel/preset-env" "^7.11.0" - "@babel/traverse" "^7.11.5" - "@rollup/plugin-babel" "^5.1.0" - "@rollup/plugin-commonjs" "^11.0.0" - "@rollup/plugin-json" "^4.0.0" - "@rollup/plugin-node-resolve" "^9.0.0" - "@rollup/plugin-replace" "^2.2.1" - "@types/jest" "^25.2.1" - "@typescript-eslint/eslint-plugin" "^2.12.0" - "@typescript-eslint/parser" "^2.12.0" - ansi-escapes "^4.2.1" - asyncro "^3.0.0" - babel-eslint "^10.0.3" - babel-plugin-annotate-pure-calls "^0.4.0" - babel-plugin-dev-expression "^0.2.1" - babel-plugin-macros "^2.6.1" - babel-plugin-polyfill-regenerator "^0.0.4" - babel-plugin-transform-rename-import "^2.3.0" - camelcase "^6.0.0" - chalk "^4.0.0" - enquirer "^2.3.4" - eslint "^6.1.0" - eslint-config-prettier "^6.0.0" - eslint-config-react-app "^5.2.1" - eslint-plugin-flowtype "^3.13.0" - eslint-plugin-import "^2.18.2" - eslint-plugin-jsx-a11y "^6.2.3" - eslint-plugin-prettier "^3.1.0" - eslint-plugin-react "^7.14.3" - eslint-plugin-react-hooks "^2.2.0" - execa "^4.0.3" - fs-extra "^9.0.0" - jest "^25.3.0" - jest-watch-typeahead "^0.5.0" - jpjs "^1.2.1" - lodash.merge "^4.6.2" - ora "^4.0.3" - pascal-case "^3.1.1" - prettier "^1.19.1" - progress-estimator "^0.2.2" - regenerator-runtime "^0.13.7" - rollup "^1.32.1" - rollup-plugin-sourcemaps "^0.6.2" - rollup-plugin-terser "^5.1.2" - rollup-plugin-typescript2 "^0.27.3" - sade "^1.4.2" - semver "^7.1.1" - shelljs "^0.8.3" - tiny-glob "^0.2.6" - ts-jest "^25.3.1" - tslib "^1.9.3" - typescript "^3.7.3" - -tslib@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.1.tgz#410eb0d113e5b6356490eec749603725b021b43e" - integrity sha512-SgIkNheinmEBgx1IUNirK0TUD4X9yjjBRTqqjggWCU3pUEqIk3/Uwl3yRixYKT6WjQuGiwDv4NomL3wqRCj+CQ== - -tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.3: - version "1.13.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043" - integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q== - -tslib@^1.9.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - -tslib@^2.1.0: +tslib@^2.1.0, tslib@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== -tsutils@^3.17.1: - version "3.17.1" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" - integrity sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g== - dependencies: - tslib "^1.8.1" - -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= - dependencies: - safe-buffer "^5.0.1" - -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= - type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" @@ -6763,11 +5146,6 @@ type-detect@4.0.8: resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== -type-fest@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1" - integrity sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ== - type-fest@^0.21.3: version "0.21.3" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" @@ -6790,38 +5168,20 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" -typescript@^3.7.3: - version "3.9.7" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa" - integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw== +typescript@^4.5.4: + version "4.5.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.5.tgz#d8c953832d28924a9e3d37c73d729c846c5896f3" + integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA== -typescript@^3.9.7: - version "3.9.10" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.10.tgz#70f3910ac7a51ed6bef79da7800690b19bf778b8" - integrity sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q== - -unicode-canonical-property-names-ecmascript@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" - integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ== - -unicode-match-property-ecmascript@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" - integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg== +unbox-primitive@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" + integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== dependencies: - unicode-canonical-property-names-ecmascript "^1.0.4" - unicode-property-aliases-ecmascript "^1.0.4" - -unicode-match-property-value-ecmascript@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz#0d91f600eeeb3096aa962b1d6fc88876e64ea531" - integrity sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ== - -unicode-property-aliases-ecmascript@^1.0.4: - version "1.1.0" - resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz#dd57a99f6207bedff4628abefb94c50db941c8f4" - integrity sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg== + function-bind "^1.1.1" + has-bigints "^1.0.1" + has-symbols "^1.0.2" + which-boxed-primitive "^1.0.2" union-value@^1.0.0: version "1.0.1" @@ -6833,16 +5193,11 @@ union-value@^1.0.0: is-extendable "^0.1.1" set-value "^2.0.1" -universalify@^0.1.0: +universalify@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== -universalify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-1.0.0.tgz#b61a1da173e8435b2fe3c67d29b9adf8594bd16d" - integrity sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug== - unset-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" @@ -6851,37 +5206,37 @@ unset-value@^1.0.0: has-value "^0.3.1" isobject "^3.0.0" -uri-js@^4.2.2: - version "4.4.0" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.0.tgz#aa714261de793e8a82347a7bcc9ce74e86f28602" - integrity sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g== - dependencies: - punycode "^2.1.0" - urix@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= +use-subscription@1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/use-subscription/-/use-subscription-1.5.1.tgz#73501107f02fad84c6dd57965beb0b75c68c42d1" + integrity sha512-Xv2a1P/yReAjAbhylMfFplFKj9GssgTwN7RlcTxBujFQcloStWNDQdc4g4NRWH9xS4i/FDk04vQBptAXoF3VcA== + dependencies: + object-assign "^4.1.1" + use@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== -uuid@^3.3.2: - version "3.4.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" - integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== +util-deprecate@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= -v8-compile-cache@^2.0.3: - version "2.1.1" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz#54bc3cdd43317bca91e35dcaf305b1a7237de745" - integrity sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ== +uuid@^8.3.0: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== -v8-to-istanbul@^4.1.3: - version "4.1.4" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-4.1.4.tgz#b97936f21c0e2d9996d4985e5c5156e9d4e49cd6" - integrity sha512-Rw6vJHj1mbdK8edjR7+zuJrpDtKIgNdAvTSAcpYfgMIw+u2dPDntD3dgN4XQFLU2/fvFQdzj+EeSGfd/jnY5fQ== +v8-to-istanbul@^7.0.0: + version "7.1.2" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz#30898d1a7fa0c84d225a2c1434fb958f290883c1" + integrity sha512-TxNb7YEUwkLXCQYeudi6lgQ/SZrzNO4kMdlqVxaZPUIUjCv6iSSypUQX70kNBSERpQ8fk48+d61FXk+tgqcWow== dependencies: "@types/istanbul-lib-coverage" "^2.0.1" convert-source-map "^1.6.0" @@ -6895,79 +5250,109 @@ validate-npm-package-license@^3.0.1: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= +vite@^2.7.13: + version "2.7.13" + resolved "https://registry.yarnpkg.com/vite/-/vite-2.7.13.tgz#99b56e27dfb1e4399e407cf94648f5c7fb9d77f5" + integrity sha512-Mq8et7f3aK0SgSxjDNfOAimZGW9XryfHRa/uV0jseQSilg+KhYDSoNb9h1rknOy6SuMkvNDLKCYAYYUMCE+IgQ== dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - -vue@3.0.7: - version "3.0.7" - resolved "https://registry.yarnpkg.com/vue/-/vue-3.0.7.tgz#8bcff51f8be570f9e4ce8cc5f52e2ab0fe3c74a1" - integrity sha512-8h4TikD+JabbMK9aRlBO4laG0AtNHRPHynxYgWZ9sq1YUPfzynd9Jeeb27XNyZytC7aCQRX9xe1+TQJuc181Tw== - dependencies: - "@vue/compiler-dom" "3.0.7" - "@vue/runtime-dom" "3.0.7" - "@vue/shared" "3.0.7" - -w3c-hr-time@^1.0.1: + esbuild "^0.13.12" + postcss "^8.4.5" + resolve "^1.20.0" + rollup "^2.59.0" + optionalDependencies: + fsevents "~2.3.2" + +vue-router@^4.0.0: + version "4.0.12" + resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-4.0.12.tgz#8dc792cddf5bb1abcc3908f9064136de7e13c460" + integrity sha512-CPXvfqe+mZLB1kBWssssTiWg4EQERyqJZes7USiqfW9B5N2x+nHlnsM1D3b5CaJ6qgCvMmYJnz+G0iWjNCvXrg== + dependencies: + "@vue/devtools-api" "^6.0.0-beta.18" + +vue@^3.2.27: + version "3.2.28" + resolved "https://registry.yarnpkg.com/vue/-/vue-3.2.28.tgz#840d193bf9713f57a365ef115c4b1286d43e0e5d" + integrity sha512-U+jBwVh3RQ9AgceLFdT7i2FFujoC+kYuGrKo5y8aLluWKZWPS40WgA2pyYHaiSX9ydCbEGr3rc/JzdqskzD95g== + dependencies: + "@vue/compiler-dom" "3.2.28" + "@vue/compiler-sfc" "3.2.28" + "@vue/runtime-dom" "3.2.28" + "@vue/server-renderer" "3.2.28" + "@vue/shared" "3.2.28" + +vue@^3.2.29: + version "3.2.29" + resolved "https://registry.yarnpkg.com/vue/-/vue-3.2.29.tgz#3571b65dbd796d3a6347e2fd45a8e6e11c13d56a" + integrity sha512-cFIwr7LkbtCRanjNvh6r7wp2yUxfxeM2yPpDQpAfaaLIGZSrUmLbNiSze9nhBJt5MrZ68Iqt0O5scwAMEVxF+Q== + dependencies: + "@vue/compiler-dom" "3.2.29" + "@vue/compiler-sfc" "3.2.29" + "@vue/runtime-dom" "3.2.29" + "@vue/server-renderer" "3.2.29" + "@vue/shared" "3.2.29" + +w3c-hr-time@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== dependencies: browser-process-hrtime "^1.0.0" -w3c-xmlserializer@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz#30485ca7d70a6fd052420a3d12fd90e6339ce794" - integrity sha512-p10l/ayESzrBMYWRID6xbuCKh2Fp77+sA0doRuGn4tTIMrrZVeqfpKjXHY+oDh3K4nLdPgNwMTVP6Vp4pvqbNg== +w3c-xmlserializer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" + integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA== dependencies: - domexception "^1.0.1" - webidl-conversions "^4.0.2" xml-name-validator "^3.0.0" walker@^1.0.7, walker@~1.0.5: - version "1.0.7" - resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" - integrity sha1-L3+bj9ENZ3JisYqITijRlhjgKPs= + version "1.0.8" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== dependencies: - makeerror "1.0.x" + makeerror "1.0.12" -wcwidth@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" - integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= - dependencies: - defaults "^1.0.3" +webidl-conversions@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" + integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== -webidl-conversions@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" - integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== +webidl-conversions@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" + integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== -whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.5: +whatwg-encoding@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== dependencies: iconv-lite "0.4.24" -whatwg-mimetype@^2.2.0, whatwg-mimetype@^2.3.0: +whatwg-mimetype@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== -whatwg-url@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06" - integrity sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg== +whatwg-url@^8.0.0, whatwg-url@^8.5.0: + version "8.7.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" + integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg== + dependencies: + lodash "^4.7.0" + tr46 "^2.1.0" + webidl-conversions "^6.1.0" + +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== dependencies: - lodash.sortby "^4.7.0" - tr46 "^1.0.1" - webidl-conversions "^4.0.2" + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" which-module@^2.0.0: version "2.0.0" @@ -6979,7 +5364,7 @@ which-pm-runs@^1.0.0: resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs= -which@^1.2.9, which@^1.3.1: +which@^1.2.9: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== @@ -6998,14 +5383,6 @@ word-wrap@~1.2.3: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== -wrap-ansi@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-3.0.1.tgz#288a04d87eda5c286e060dfe8f135ce8d007f8ba" - integrity sha1-KIoE2H7aXChuBg3+jxNc6NAH+Lo= - dependencies: - string-width "^2.1.1" - strip-ansi "^4.0.0" - wrap-ansi@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" @@ -7039,49 +5416,42 @@ write-file-atomic@^3.0.0: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" -write@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" - integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== - dependencies: - mkdirp "^0.5.1" - -ws@^7.0.0: - version "7.3.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.3.1.tgz#d0547bf67f7ce4f12a72dfe31262c68d7dc551c8" - integrity sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA== +ws@^7.4.6: + version "7.5.6" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.6.tgz#e59fc509fb15ddfb65487ee9765c5a51dec5fe7b" + integrity sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA== xml-name-validator@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== -xmlchars@^2.1.1: +xmlchars@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== y18n@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" - integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== + version "4.0.3" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" + integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + yaml@^1.10.0, yaml@^1.10.2: version "1.10.2" resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== -yaml@^1.7.2: - version "1.10.0" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.0.tgz#3b593add944876077d4d683fee01081bd9fff31e" - integrity sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg== - -yargs-parser@18.x, yargs-parser@^18.1.2: +yargs-parser@^18.1.2: version "18.1.3" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== @@ -7089,7 +5459,7 @@ yargs-parser@18.x, yargs-parser@^18.1.2: camelcase "^5.0.0" decamelize "^1.2.0" -yargs@^15.3.1: +yargs@^15.4.1: version "15.4.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==