Improve overal codebase, use modern tech like esbuild and TypeScript 4! (#1055)
* use esbuild for React instead of tsdx * remove tsdx from Vue * use consistent names * add jest and prettier * update scripts * ignore some folders for prettier * run lint script instead of tsdx lint * run prettier en-masse This has a few changes because of the new prettier version. * bump typescript to latest version * make typescript happy * cleanup playground package.json * make esbuild a dev dependency * make scripts consistent * fix husky hooks * add dedicated watch script * add `yarn playground-react` and `yarn react-playground` (alias) This will make sure to run a watcher for the actual @headlessui/react package, and start a development server in the playground-react package. * ignore formatting in the .next folder * run prettier on playground-react package * setup playground-vue Still not 100% working, but getting there! * add playground aliases in @headlessui/vue and @headlessui/react This allows you to run `yarn react playground` or `yarn vue playground` from the root. * add `clean` script * move examples folder in playground-vue to root * ensure new lines for consistency in scripts * fix typescript issue * fix typescript issues in playgrounds * make sure to run prettier on everything it can * run prettier on all files * improve error output If you minify the code, then it could happen that the errors are a bit obscure. This will hardcode the component name to improve errors. * add the `prettier-plugin-tailwindcss` plugin, party! * update changelog
This commit is contained in:
@@ -46,4 +46,3 @@ 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.
|
||||
|
||||
|
||||
@@ -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.'
|
||||
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
dist/
|
||||
node_modules/
|
||||
coverage/
|
||||
.next/
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"minify": false,
|
||||
"jsc": {
|
||||
"parser": {
|
||||
"syntax": "typescript",
|
||||
"tsx": true,
|
||||
"decorators": false,
|
||||
"dynamicImport": false
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-4
@@ -12,6 +12,7 @@ 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
|
||||
|
||||
@@ -23,6 +24,7 @@ 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
|
||||
|
||||
@@ -107,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))
|
||||
@@ -127,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))
|
||||
@@ -141,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))
|
||||
|
||||
@@ -153,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))
|
||||
|
||||
|
||||
@@ -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**.
|
||||
|
||||
|
||||
@@ -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: ['<rootDir>../../jest/custom-matchers.ts'],
|
||||
globals: {
|
||||
'ts-jest': {
|
||||
isolatedModules: true,
|
||||
tsConfig: '<rootDir>/tsconfig.tsdx.json',
|
||||
},
|
||||
transform: {
|
||||
'^.+\\.(t|j)sx?$': '@swc/jest',
|
||||
},
|
||||
},
|
||||
options
|
||||
|
||||
+18
-6
@@ -14,10 +14,13 @@
|
||||
"react-playground": "yarn workspace playground-react dev",
|
||||
"playground-react": "yarn workspace playground-react dev",
|
||||
"vue": "yarn workspace @headlessui/vue",
|
||||
"shared": "yarn workspace @headlessui/shared",
|
||||
"playground-vue": "yarn workspace playground-vue dev",
|
||||
"vue-playground": "yarn workspace playground-vue dev",
|
||||
"clean": "yarn workspaces run clean",
|
||||
"build": "yarn workspaces run build",
|
||||
"test": "./scripts/test.sh",
|
||||
"lint": "./scripts/lint.sh"
|
||||
"lint": "./scripts/lint.sh",
|
||||
"lint-check": "CI=true ./scripts/lint.sh"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
@@ -25,7 +28,7 @@
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,jsx,ts,tsx}": "tsdx lint"
|
||||
"*": "yarn lint-check"
|
||||
},
|
||||
"prettier": {
|
||||
"printWidth": 100,
|
||||
@@ -34,12 +37,21 @@
|
||||
"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",
|
||||
"rimraf": "^3.0.2",
|
||||
"tslib": "^2.3.1",
|
||||
"typescript": "^4.5.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"prettier-plugin-tailwindcss": "^0.1.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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')
|
||||
}
|
||||
@@ -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,10 +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",
|
||||
"watch": "../../scripts/watch.sh",
|
||||
"lint": "../../scripts/lint.sh"
|
||||
"lint": "../../scripts/lint.sh",
|
||||
"playground": "yarn workspace playground-react dev",
|
||||
"clean": "rimraf ./dist"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16 || ^17 || ^18",
|
||||
@@ -39,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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -481,7 +481,7 @@ describe('Rendering', () => {
|
||||
<Combobox.Input onChange={NOOP} />
|
||||
<Combobox.Button>Trigger</Combobox.Button>
|
||||
<Combobox.Options>
|
||||
{data => (
|
||||
{(data) => (
|
||||
<>
|
||||
<Combobox.Option value="a">{JSON.stringify(data)}</Combobox.Option>
|
||||
</>
|
||||
@@ -639,10 +639,10 @@ describe('Rendering composition', () => {
|
||||
<Combobox.Input onChange={NOOP} />
|
||||
<Combobox.Button>Trigger</Combobox.Button>
|
||||
<Combobox.Options>
|
||||
<Combobox.Option value="a" className={bag => JSON.stringify(bag)}>
|
||||
<Combobox.Option value="a" className={(bag) => JSON.stringify(bag)}>
|
||||
Option A
|
||||
</Combobox.Option>
|
||||
<Combobox.Option value="b" disabled className={bag => JSON.stringify(bag)}>
|
||||
<Combobox.Option value="b" disabled className={(bag) => JSON.stringify(bag)}>
|
||||
Option B
|
||||
</Combobox.Option>
|
||||
<Combobox.Option value="c" className="no-special-treatment">
|
||||
@@ -738,7 +738,7 @@ describe('Rendering composition', () => {
|
||||
await click(getComboboxButton())
|
||||
|
||||
// Verify options are buttons now
|
||||
getComboboxOptions().forEach(option => assertComboboxOption(option, { tag: 'button' }))
|
||||
getComboboxOptions().forEach((option) => assertComboboxOption(option, { tag: 'button' }))
|
||||
})
|
||||
)
|
||||
})
|
||||
@@ -767,7 +767,7 @@ describe('Composition', () => {
|
||||
<Debug name="Transition" fn={orderFn} />
|
||||
<Combobox.Options>
|
||||
<Combobox.Option value="a">
|
||||
{data => (
|
||||
{(data) => (
|
||||
<>
|
||||
{JSON.stringify(data)}
|
||||
<Debug name="Combobox.Option" fn={orderFn} />
|
||||
@@ -855,7 +855,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option, { selected: false }))
|
||||
options.forEach((option) => assertComboboxOption(option, { selected: false }))
|
||||
|
||||
assertNoActiveComboboxOption()
|
||||
assertNoSelectedComboboxOption()
|
||||
@@ -1026,7 +1026,7 @@ describe('Keyboard interactions', () => {
|
||||
<Combobox.Input onChange={NOOP} />
|
||||
<Combobox.Button>Trigger</Combobox.Button>
|
||||
<Combobox.Options>
|
||||
{myOptions.map(myOption => (
|
||||
{myOptions.map((myOption) => (
|
||||
<Combobox.Option key={myOption.id} value={myOption}>
|
||||
{myOption.name}
|
||||
</Combobox.Option>
|
||||
@@ -1142,7 +1142,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
assertNoActiveComboboxOption()
|
||||
})
|
||||
)
|
||||
@@ -1383,7 +1383,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
|
||||
// Verify that the first combobox option is active
|
||||
assertNoActiveComboboxOption()
|
||||
@@ -1539,7 +1539,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
|
||||
// Verify that the first combobox option is active
|
||||
assertNoActiveComboboxOption()
|
||||
@@ -1695,7 +1695,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
|
||||
// ! ALERT: The LAST option should now be active
|
||||
assertActiveComboboxOption(options[2])
|
||||
@@ -1843,7 +1843,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
assertActiveComboboxOption(options[0])
|
||||
})
|
||||
)
|
||||
@@ -1890,7 +1890,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
|
||||
// ! ALERT: The LAST option should now be active
|
||||
assertActiveComboboxOption(options[2])
|
||||
@@ -2039,7 +2039,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
assertActiveComboboxOption(options[0])
|
||||
})
|
||||
)
|
||||
@@ -2059,7 +2059,7 @@ describe('Keyboard interactions', () => {
|
||||
return (
|
||||
<Combobox
|
||||
value={value}
|
||||
onChange={value => {
|
||||
onChange={(value) => {
|
||||
setValue(value)
|
||||
handleChange(value)
|
||||
}}
|
||||
@@ -2305,7 +2305,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
|
||||
// Verify that the first combobox option is active
|
||||
assertNoActiveComboboxOption()
|
||||
@@ -2446,7 +2446,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
assertNoActiveComboboxOption()
|
||||
|
||||
// We should be able to go down once
|
||||
@@ -2496,7 +2496,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
assertNoActiveComboboxOption()
|
||||
|
||||
// We should be able to go down once
|
||||
@@ -2536,7 +2536,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
assertNoActiveComboboxOption()
|
||||
|
||||
// Open combobox
|
||||
@@ -2587,7 +2587,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
|
||||
// Verify that the first combobox option is active
|
||||
assertNoActiveComboboxOption()
|
||||
@@ -2729,7 +2729,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
assertNoActiveComboboxOption()
|
||||
|
||||
// We should be able to go down once
|
||||
@@ -2779,7 +2779,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
assertNoActiveComboboxOption()
|
||||
|
||||
// We should be able to go down once
|
||||
@@ -2819,7 +2819,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
assertNoActiveComboboxOption()
|
||||
|
||||
// Open combobox
|
||||
@@ -2869,7 +2869,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
|
||||
// ! ALERT: The LAST option should now be active
|
||||
assertActiveComboboxOption(options[2])
|
||||
@@ -3017,7 +3017,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
assertActiveComboboxOption(options[0])
|
||||
})
|
||||
)
|
||||
@@ -3053,7 +3053,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
assertNoActiveComboboxOption()
|
||||
|
||||
// Going up or down should select the single available option
|
||||
@@ -3108,7 +3108,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
assertActiveComboboxOption(options[2])
|
||||
|
||||
// We should be able to go down once
|
||||
@@ -3167,7 +3167,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
|
||||
// ! ALERT: The LAST option should now be active
|
||||
assertActiveComboboxOption(options[2])
|
||||
@@ -3316,7 +3316,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
assertActiveComboboxOption(options[0])
|
||||
})
|
||||
)
|
||||
@@ -3894,14 +3894,16 @@ describe('Keyboard interactions', () => {
|
||||
let filteredPeople =
|
||||
query === ''
|
||||
? props.people
|
||||
: props.people.filter(person => person.name.toLowerCase().includes(query.toLowerCase()))
|
||||
: props.people.filter((person) =>
|
||||
person.name.toLowerCase().includes(query.toLowerCase())
|
||||
)
|
||||
|
||||
return (
|
||||
<Combobox value={value} onChange={setValue}>
|
||||
<Combobox.Input onChange={event => setQuery(event.target.value)} />
|
||||
<Combobox.Input onChange={(event) => setQuery(event.target.value)} />
|
||||
<Combobox.Button>Trigger</Combobox.Button>
|
||||
<Combobox.Options>
|
||||
{filteredPeople.map(person => (
|
||||
{filteredPeople.map((person) => (
|
||||
<Combobox.Option key={person.value} value={person.value} disabled={person.disabled}>
|
||||
{person.name}
|
||||
</Combobox.Option>
|
||||
@@ -4207,7 +4209,7 @@ describe('Mouse interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
})
|
||||
)
|
||||
|
||||
@@ -4752,7 +4754,7 @@ describe('Mouse interactions', () => {
|
||||
return (
|
||||
<Combobox
|
||||
value={value}
|
||||
onChange={value => {
|
||||
onChange={(value) => {
|
||||
setValue(value)
|
||||
handleChange(value)
|
||||
}}
|
||||
@@ -4804,7 +4806,7 @@ describe('Mouse interactions', () => {
|
||||
return (
|
||||
<Combobox
|
||||
value={value}
|
||||
onChange={value => {
|
||||
onChange={(value) => {
|
||||
setValue(value)
|
||||
handleChange(value)
|
||||
}}
|
||||
|
||||
@@ -123,8 +123,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.activeOptionIndex === activeOptionIndex) return state
|
||||
@@ -163,7 +163,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)
|
||||
|
||||
@@ -284,12 +284,13 @@ export function Combobox<TTag extends ElementType = typeof DEFAULT_COMBOBOX_TAG,
|
||||
}, [onChange, propsRef])
|
||||
|
||||
useIsoMorphicEffect(() => 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 (comboboxState !== ComboboxStates.Open) return
|
||||
@@ -333,7 +334,7 @@ export function Combobox<TTag extends ElementType = typeof DEFAULT_COMBOBOX_TAG,
|
||||
|
||||
let selectOption = useCallback(
|
||||
(id: string) => {
|
||||
let option = options.find(item => item.id === id)
|
||||
let option = options.find((item) => item.id === id)
|
||||
if (!option) return
|
||||
|
||||
let { dataRef } = option
|
||||
@@ -418,7 +419,7 @@ let Input = forwardRefWithAs(function Input<
|
||||
ref: Ref<HTMLInputElement>
|
||||
) {
|
||||
let { value, onChange, displayValue, ...passThroughProps } = props
|
||||
let [state, dispatch] = useComboboxContext([Combobox.name, Input.name].join('.'))
|
||||
let [state, dispatch] = useComboboxContext('Combobox.Input')
|
||||
let actions = useComboboxActions()
|
||||
|
||||
let inputRef = useSyncRefs(state.inputRef, ref)
|
||||
@@ -579,7 +580,7 @@ let Button = forwardRefWithAs(function Button<TTag extends ElementType = typeof
|
||||
props: Props<TTag, ButtonRenderPropArg, ButtonPropsWeControl>,
|
||||
ref: Ref<HTMLButtonElement>
|
||||
) {
|
||||
let [state, dispatch] = useComboboxContext([Combobox.name, Button.name].join('.'))
|
||||
let [state, dispatch] = useComboboxContext('Combobox.Button')
|
||||
let actions = useComboboxActions()
|
||||
let buttonRef = useSyncRefs(state.buttonRef, ref)
|
||||
|
||||
@@ -693,12 +694,13 @@ type LabelPropsWeControl = 'id' | 'ref' | 'onClick'
|
||||
function Label<TTag extends ElementType = typeof DEFAULT_LABEL_TAG>(
|
||||
props: Props<TTag, LabelRenderPropArg, LabelPropsWeControl>
|
||||
) {
|
||||
let [state] = useComboboxContext([Combobox.name, Label.name].join('.'))
|
||||
let [state] = useComboboxContext('Combobox.Label')
|
||||
let id = `headlessui-combobox-label-${useId()}`
|
||||
|
||||
let handleClick = useCallback(() => state.inputRef.current?.focus({ preventScroll: true }), [
|
||||
state.inputRef,
|
||||
])
|
||||
let handleClick = useCallback(
|
||||
() => state.inputRef.current?.focus({ preventScroll: true }),
|
||||
[state.inputRef]
|
||||
)
|
||||
|
||||
let slot = useMemo<LabelRenderPropArg>(
|
||||
() => ({ open: state.comboboxState === ComboboxStates.Open, disabled: state.disabled }),
|
||||
@@ -737,7 +739,7 @@ let Options = forwardRefWithAs(function Options<
|
||||
PropsForFeatures<typeof OptionsRenderFeatures>,
|
||||
ref: Ref<HTMLUListElement>
|
||||
) {
|
||||
let [state, dispatch] = useComboboxContext([Combobox.name, Options.name].join('.'))
|
||||
let [state, dispatch] = useComboboxContext('Combobox.Options')
|
||||
let optionsRef = useSyncRefs(state.optionsRef, ref)
|
||||
|
||||
let id = `headlessui-combobox-options-${useId()}`
|
||||
@@ -751,10 +753,10 @@ let Options = forwardRefWithAs(function Options<
|
||||
return state.comboboxState === ComboboxStates.Open
|
||||
})()
|
||||
|
||||
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 handleLeave = useCallback(() => {
|
||||
if (state.comboboxState !== ComboboxStates.Open) return
|
||||
@@ -820,7 +822,7 @@ function Option<
|
||||
}
|
||||
) {
|
||||
let { disabled = false, value, ...passthroughProps } = props
|
||||
let [state, dispatch] = useComboboxContext([Combobox.name, Option.name].join('.'))
|
||||
let [state, dispatch] = useComboboxContext('Combobox.Option')
|
||||
let actions = useComboboxActions()
|
||||
let id = `headlessui-combobox-option-${useId()}`
|
||||
let active =
|
||||
@@ -886,11 +888,10 @@ function Option<
|
||||
dispatch({ type: ActionTypes.GoToOption, focus: Focus.Nothing })
|
||||
}, [disabled, active, dispatch])
|
||||
|
||||
let slot = useMemo<OptionRenderPropArg>(() => ({ active, selected, disabled }), [
|
||||
active,
|
||||
selected,
|
||||
disabled,
|
||||
])
|
||||
let slot = useMemo<OptionRenderPropArg>(
|
||||
() => ({ active, selected, disabled }),
|
||||
[active, selected, disabled]
|
||||
)
|
||||
|
||||
let propsWeControl = {
|
||||
id,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -143,7 +143,7 @@ describe('Rendering', () => {
|
||||
Trigger
|
||||
</button>
|
||||
<Dialog open={isOpen} onClose={setIsOpen}>
|
||||
{data => (
|
||||
{(data) => (
|
||||
<>
|
||||
<pre>{JSON.stringify(data)}</pre>
|
||||
<TabSentinel />
|
||||
@@ -204,7 +204,7 @@ describe('Rendering', () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<button id="trigger" onClick={() => setIsOpen(v => !v)}>
|
||||
<button id="trigger" onClick={() => setIsOpen((v) => !v)}>
|
||||
Trigger
|
||||
</button>
|
||||
<Dialog open={isOpen} onClose={setIsOpen} unmount={false}>
|
||||
@@ -239,7 +239,7 @@ describe('Rendering', () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<button id="trigger" onClick={() => setIsOpen(v => !v)}>
|
||||
<button id="trigger" onClick={() => setIsOpen((v) => !v)}>
|
||||
Trigger
|
||||
</button>
|
||||
|
||||
@@ -277,7 +277,7 @@ describe('Rendering', () => {
|
||||
let [isOpen, setIsOpen] = useState(false)
|
||||
return (
|
||||
<>
|
||||
<button id="trigger" onClick={() => setIsOpen(v => !v)}>
|
||||
<button id="trigger" onClick={() => setIsOpen((v) => !v)}>
|
||||
Trigger
|
||||
</button>
|
||||
<Dialog open={isOpen} onClose={setIsOpen}>
|
||||
@@ -400,7 +400,7 @@ describe('Keyboard interactions', () => {
|
||||
let [isOpen, setIsOpen] = useState(false)
|
||||
return (
|
||||
<>
|
||||
<button id="trigger" onClick={() => setIsOpen(v => !v)}>
|
||||
<button id="trigger" onClick={() => setIsOpen((v) => !v)}>
|
||||
Trigger
|
||||
</button>
|
||||
<Dialog open={isOpen} onClose={setIsOpen}>
|
||||
@@ -438,7 +438,7 @@ describe('Keyboard interactions', () => {
|
||||
let [isOpen, setIsOpen] = useState(false)
|
||||
return (
|
||||
<>
|
||||
<button id="trigger" onClick={() => setIsOpen(v => !v)}>
|
||||
<button id="trigger" onClick={() => setIsOpen((v) => !v)}>
|
||||
Trigger
|
||||
</button>
|
||||
<Dialog open={isOpen} onClose={setIsOpen}>
|
||||
@@ -477,14 +477,14 @@ describe('Keyboard interactions', () => {
|
||||
let [isOpen, setIsOpen] = useState(false)
|
||||
return (
|
||||
<>
|
||||
<button id="trigger" onClick={() => setIsOpen(v => !v)}>
|
||||
<button id="trigger" onClick={() => setIsOpen((v) => !v)}>
|
||||
Trigger
|
||||
</button>
|
||||
<Dialog open={isOpen} onClose={setIsOpen}>
|
||||
Contents
|
||||
<input
|
||||
id="name"
|
||||
onKeyDown={event => {
|
||||
onKeyDown={(event) => {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
}}
|
||||
@@ -525,7 +525,7 @@ describe('Mouse interactions', () => {
|
||||
let [isOpen, setIsOpen] = useState(false)
|
||||
return (
|
||||
<>
|
||||
<button id="trigger" onClick={() => setIsOpen(v => !v)}>
|
||||
<button id="trigger" onClick={() => setIsOpen((v) => !v)}>
|
||||
Trigger
|
||||
</button>
|
||||
<Dialog open={isOpen} onClose={setIsOpen}>
|
||||
@@ -559,7 +559,7 @@ describe('Mouse interactions', () => {
|
||||
let [isOpen, setIsOpen] = useState(false)
|
||||
return (
|
||||
<>
|
||||
<button id="trigger" onClick={() => setIsOpen(v => !v)}>
|
||||
<button id="trigger" onClick={() => setIsOpen((v) => !v)}>
|
||||
Trigger
|
||||
</button>
|
||||
<Dialog open={isOpen} onClose={setIsOpen}>
|
||||
@@ -595,7 +595,7 @@ describe('Mouse interactions', () => {
|
||||
let [isOpen, setIsOpen] = useState(false)
|
||||
return (
|
||||
<>
|
||||
<button onClick={() => setIsOpen(v => !v)}>Trigger</button>
|
||||
<button onClick={() => setIsOpen((v) => !v)}>Trigger</button>
|
||||
<Dialog open={isOpen} onClose={setIsOpen}>
|
||||
Contents
|
||||
<TabSentinel />
|
||||
@@ -630,7 +630,7 @@ describe('Mouse interactions', () => {
|
||||
return (
|
||||
<>
|
||||
<button>Hello</button>
|
||||
<button onClick={() => setIsOpen(v => !v)}>Trigger</button>
|
||||
<button onClick={() => setIsOpen((v) => !v)}>Trigger</button>
|
||||
<Dialog open={isOpen} onClose={setIsOpen}>
|
||||
Contents
|
||||
<TabSentinel />
|
||||
|
||||
@@ -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<DialogRenderPropArg>(() => ({ open: dialogState === DialogStates.Open }), [
|
||||
dialogState,
|
||||
])
|
||||
let slot = useMemo<DialogRenderPropArg>(
|
||||
() => ({ 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<TTag, OverlayRenderPropArg, OverlayPropsWeControl>, ref: Ref<HTMLDivElement>) {
|
||||
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<OverlayRenderPropArg>(() => ({ open: dialogState === DialogStates.Open }), [
|
||||
dialogState,
|
||||
])
|
||||
let slot = useMemo<OverlayRenderPropArg>(
|
||||
() => ({ open: dialogState === DialogStates.Open }),
|
||||
[dialogState]
|
||||
)
|
||||
let propsWeControl = {
|
||||
ref: overlayRef,
|
||||
id,
|
||||
@@ -394,7 +396,7 @@ type TitlePropsWeControl = 'id'
|
||||
function Title<TTag extends ElementType = typeof DEFAULT_TITLE_TAG>(
|
||||
props: Props<TTag, TitleRenderPropArg, TitlePropsWeControl>
|
||||
) {
|
||||
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<TTag extends ElementType = typeof DEFAULT_TITLE_TAG>(
|
||||
return () => setTitleId(null)
|
||||
}, [id, setTitleId])
|
||||
|
||||
let slot = useMemo<TitleRenderPropArg>(() => ({ open: dialogState === DialogStates.Open }), [
|
||||
dialogState,
|
||||
])
|
||||
let slot = useMemo<TitleRenderPropArg>(
|
||||
() => ({ open: dialogState === DialogStates.Open }),
|
||||
[dialogState]
|
||||
)
|
||||
let propsWeControl = { id }
|
||||
let passthroughProps = props
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ jest.mock('../../hooks/use-id')
|
||||
afterAll(() => jest.restoreAllMocks())
|
||||
|
||||
function nextFrame() {
|
||||
return new Promise<void>(resolve => {
|
||||
return new Promise<void>((resolve) => {
|
||||
requestAnimationFrame(() => {
|
||||
requestAnimationFrame(() => {
|
||||
resolve()
|
||||
|
||||
@@ -68,14 +68,14 @@ let reducers: {
|
||||
action: Extract<Actions, { type: P }>
|
||||
) => 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<TTag extends ElementType = typeof
|
||||
props: Props<TTag, ButtonRenderPropArg, ButtonPropsWeControl>,
|
||||
ref: Ref<HTMLButtonElement>
|
||||
) {
|
||||
let [state, dispatch] = useDisclosureContext([Disclosure.name, Button.name].join('.'))
|
||||
let [state, dispatch] = useDisclosureContext('Disclosure.Button')
|
||||
let internalButtonRef = useRef<HTMLButtonElement | null>(null)
|
||||
let buttonRef = useSyncRefs(internalButtonRef, ref)
|
||||
|
||||
@@ -334,8 +334,8 @@ let Panel = forwardRefWithAs(function Panel<TTag extends ElementType = typeof DE
|
||||
PropsForFeatures<typeof PanelRenderFeatures>,
|
||||
ref: Ref<HTMLDivElement>
|
||||
) {
|
||||
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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -56,6 +56,7 @@ describe('safeguards', () => {
|
||||
])(
|
||||
'should error when we are using a <%s /> without a parent <Listbox />',
|
||||
suppressConsoleLogs((name, Component) => {
|
||||
// @ts-expect-error This is fine
|
||||
expect(() => render(createElement(Component))).toThrowError(
|
||||
`<${name} /> is missing a parent <Listbox /> component.`
|
||||
)
|
||||
@@ -396,7 +397,7 @@ describe('Rendering', () => {
|
||||
<Listbox value={undefined} onChange={console.log}>
|
||||
<Listbox.Button>Trigger</Listbox.Button>
|
||||
<Listbox.Options>
|
||||
{data => (
|
||||
{(data) => (
|
||||
<>
|
||||
<Listbox.Option value="a">{JSON.stringify(data)}</Listbox.Option>
|
||||
</>
|
||||
@@ -547,10 +548,10 @@ describe('Rendering composition', () => {
|
||||
<Listbox value={undefined} onChange={console.log}>
|
||||
<Listbox.Button>Trigger</Listbox.Button>
|
||||
<Listbox.Options>
|
||||
<Listbox.Option value="a" className={bag => JSON.stringify(bag)}>
|
||||
<Listbox.Option value="a" className={(bag) => JSON.stringify(bag)}>
|
||||
Option A
|
||||
</Listbox.Option>
|
||||
<Listbox.Option value="b" disabled className={bag => JSON.stringify(bag)}>
|
||||
<Listbox.Option value="b" disabled className={(bag) => JSON.stringify(bag)}>
|
||||
Option B
|
||||
</Listbox.Option>
|
||||
<Listbox.Option value="c" className="no-special-treatment">
|
||||
@@ -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', () => {
|
||||
<Debug name="Transition" fn={orderFn} />
|
||||
<Listbox.Options>
|
||||
<Listbox.Option value="a">
|
||||
{data => (
|
||||
{(data) => (
|
||||
<>
|
||||
{JSON.stringify(data)}
|
||||
<Debug name="Listbox.Option" fn={orderFn} />
|
||||
@@ -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', () => {
|
||||
<Listbox value={selectedOption} onChange={console.log}>
|
||||
<Listbox.Button>Trigger</Listbox.Button>
|
||||
<Listbox.Options>
|
||||
{myOptions.map(myOption => (
|
||||
{myOptions.map((myOption) => (
|
||||
<Listbox.Option key={myOption.id} value={myOption}>
|
||||
{myOption.name}
|
||||
</Listbox.Option>
|
||||
@@ -1139,7 +1140,7 @@ describe('Keyboard interactions', () => {
|
||||
return (
|
||||
<Listbox
|
||||
value={value}
|
||||
onChange={value => {
|
||||
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 (
|
||||
<Listbox
|
||||
value={value}
|
||||
onChange={value => {
|
||||
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 (
|
||||
<Listbox
|
||||
value={value}
|
||||
onChange={value => {
|
||||
onChange={(value) => {
|
||||
setValue(value)
|
||||
handleChange(value)
|
||||
}}
|
||||
@@ -3777,7 +3778,7 @@ describe('Mouse interactions', () => {
|
||||
return (
|
||||
<Listbox
|
||||
value={value}
|
||||
onChange={value => {
|
||||
onChange={(value) => {
|
||||
setValue(value)
|
||||
handleChange(value)
|
||||
}}
|
||||
|
||||
@@ -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<TTag extends ElementType = typeof DEFAULT_LISTBOX_TAG, T
|
||||
propsRef.current.onChange = onChange
|
||||
}, [onChange, propsRef])
|
||||
useIsoMorphicEffect(() => 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<TTag extends ElementType = typeof
|
||||
props: Props<TTag, ButtonRenderPropArg, ButtonPropsWeControl>,
|
||||
ref: Ref<HTMLButtonElement>
|
||||
) {
|
||||
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<TTag extends ElementType = typeof DEFAULT_LABEL_TAG>(
|
||||
props: Props<TTag, LabelRenderPropArg, LabelPropsWeControl>
|
||||
) {
|
||||
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<LabelRenderPropArg>(
|
||||
() => ({ open: state.listboxState === ListboxStates.Open, disabled: state.disabled }),
|
||||
@@ -466,7 +468,7 @@ let Options = forwardRefWithAs(function Options<
|
||||
PropsForFeatures<typeof OptionsRenderFeatures>,
|
||||
ref: Ref<HTMLUListElement>
|
||||
) {
|
||||
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<OptionsRenderPropArg>(
|
||||
() => ({ 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<OptionRenderPropArg>(() => ({ active, selected, disabled }), [
|
||||
active,
|
||||
selected,
|
||||
disabled,
|
||||
])
|
||||
let slot = useMemo<OptionRenderPropArg>(
|
||||
() => ({ active, selected, disabled }),
|
||||
[active, selected, disabled]
|
||||
)
|
||||
let propsWeControl = {
|
||||
id,
|
||||
role: 'option',
|
||||
|
||||
@@ -253,7 +253,7 @@ describe('Rendering', () => {
|
||||
<Menu>
|
||||
<Menu.Button>Trigger</Menu.Button>
|
||||
<Menu.Items>
|
||||
{data => (
|
||||
{(data) => (
|
||||
<>
|
||||
<Menu.Item as="a">{JSON.stringify(data)}</Menu.Item>
|
||||
</>
|
||||
@@ -403,10 +403,10 @@ describe('Rendering composition', () => {
|
||||
<Menu>
|
||||
<Menu.Button>Trigger</Menu.Button>
|
||||
<Menu.Items>
|
||||
<Menu.Item as="a" className={bag => JSON.stringify(bag)}>
|
||||
<Menu.Item as="a" className={(bag) => JSON.stringify(bag)}>
|
||||
Item A
|
||||
</Menu.Item>
|
||||
<Menu.Item as="a" disabled className={bag => JSON.stringify(bag)}>
|
||||
<Menu.Item as="a" disabled className={(bag) => JSON.stringify(bag)}>
|
||||
Item B
|
||||
</Menu.Item>
|
||||
<Menu.Item as="a" className="no-special-treatment">
|
||||
@@ -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', () => {
|
||||
<Menu.Button>Trigger</Menu.Button>
|
||||
<div className="outer">
|
||||
<Menu.Items>
|
||||
<div className="py-1 inner">
|
||||
<div className="inner py-1">
|
||||
<Menu.Item as="button">Item A</Menu.Item>
|
||||
<Menu.Item as="button">Item B</Menu.Item>
|
||||
</div>
|
||||
<div className="py-1 inner">
|
||||
<div className="inner py-1">
|
||||
<Menu.Item as="button">Item C</Menu.Item>
|
||||
<Menu.Item>
|
||||
<div>
|
||||
@@ -508,7 +508,7 @@ describe('Rendering composition', () => {
|
||||
</div>
|
||||
</Menu.Item>
|
||||
</div>
|
||||
<div className="py-1 inner">
|
||||
<div className="inner py-1">
|
||||
<form className="inner">
|
||||
<Menu.Item as="button">Item E</Menu.Item>
|
||||
</form>
|
||||
@@ -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', () => {
|
||||
<Debug name="Transition" fn={orderFn} />
|
||||
<Menu.Items>
|
||||
<Menu.Item as="a">
|
||||
{data => (
|
||||
{(data) => (
|
||||
<>
|
||||
{JSON.stringify(data)}
|
||||
<Debug name="Menu.Item" fn={orderFn} />
|
||||
@@ -611,7 +611,7 @@ describe('Composition', () => {
|
||||
<Debug name="Transition" fn={orderFn} />
|
||||
<Menu.Items>
|
||||
<Menu.Item as="a">
|
||||
{data => (
|
||||
{(data) => (
|
||||
<>
|
||||
{JSON.stringify(data)}
|
||||
<Debug name="Menu.Item" fn={orderFn} />
|
||||
@@ -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))
|
||||
})
|
||||
)
|
||||
|
||||
|
||||
@@ -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<TTag extends ElementType = typeof DEFAULT_MENU_TAG>(
|
||||
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<TTag extends ElementType = typeof DEFAULT_MENU_TAG>(
|
||||
}
|
||||
})
|
||||
|
||||
let slot = useMemo<MenuRenderPropArg>(() => ({ open: menuState === MenuStates.Open }), [
|
||||
menuState,
|
||||
])
|
||||
let slot = useMemo<MenuRenderPropArg>(
|
||||
() => ({ open: menuState === MenuStates.Open }),
|
||||
[menuState]
|
||||
)
|
||||
|
||||
return (
|
||||
<MenuContext.Provider value={reducerBag}>
|
||||
@@ -249,7 +250,7 @@ let Button = forwardRefWithAs(function Button<TTag extends ElementType = typeof
|
||||
props: Props<TTag, ButtonRenderPropArg, ButtonPropsWeControl>,
|
||||
ref: Ref<HTMLButtonElement>
|
||||
) {
|
||||
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<TTag extends ElementType = typeof
|
||||
[dispatch, d, state, props.disabled]
|
||||
)
|
||||
|
||||
let slot = useMemo<ButtonRenderPropArg>(() => ({ open: state.menuState === MenuStates.Open }), [
|
||||
state,
|
||||
])
|
||||
let slot = useMemo<ButtonRenderPropArg>(
|
||||
() => ({ open: state.menuState === MenuStates.Open }),
|
||||
[state]
|
||||
)
|
||||
let passthroughProps = props
|
||||
let propsWeControl = {
|
||||
ref: buttonRef,
|
||||
@@ -352,7 +354,7 @@ let Items = forwardRefWithAs(function Items<TTag extends ElementType = typeof DE
|
||||
PropsForFeatures<typeof ItemsRenderFeatures>,
|
||||
ref: Ref<HTMLDivElement>
|
||||
) {
|
||||
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<TTag extends ElementType = typeof DE
|
||||
}
|
||||
}, [])
|
||||
|
||||
let slot = useMemo<ItemsRenderPropArg>(() => ({ open: state.menuState === MenuStates.Open }), [
|
||||
state,
|
||||
])
|
||||
let slot = useMemo<ItemsRenderPropArg>(
|
||||
() => ({ 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<TTag extends ElementType = typeof DEFAULT_ITEM_TAG>(
|
||||
}
|
||||
) {
|
||||
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
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ jest.mock('../../hooks/use-id')
|
||||
afterAll(() => jest.restoreAllMocks())
|
||||
|
||||
function nextFrame() {
|
||||
return new Promise<void>(resolve => {
|
||||
return new Promise<void>((resolve) => {
|
||||
requestAnimationFrame(() => {
|
||||
requestAnimationFrame(() => {
|
||||
resolve()
|
||||
|
||||
@@ -75,7 +75,7 @@ let reducers: {
|
||||
action: Extract<Actions, { type: P }>
|
||||
) => StateDefinition
|
||||
} = {
|
||||
[ActionTypes.TogglePopover]: state => ({
|
||||
[ActionTypes.TogglePopover]: (state) => ({
|
||||
...state,
|
||||
popoverState: match(state.popoverState, {
|
||||
[PopoverStates.Open]: PopoverStates.Closed,
|
||||
@@ -217,7 +217,7 @@ export function Popover<TTag extends ElementType = typeof DEFAULT_POPOVER_TAG>(
|
||||
)
|
||||
|
||||
// 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<TTag extends ElementType = typeof
|
||||
props: Props<TTag, ButtonRenderPropArg, ButtonPropsWeControl>,
|
||||
ref: Ref<HTMLButtonElement>
|
||||
) {
|
||||
let [state, dispatch] = usePopoverContext([Popover.name, Button.name].join('.'))
|
||||
let [state, dispatch] = usePopoverContext('Popover.Button')
|
||||
let internalButtonRef = useRef<HTMLButtonElement | null>(null)
|
||||
|
||||
let groupContext = usePopoverGroupContext()
|
||||
@@ -308,7 +308,7 @@ let Button = forwardRefWithAs(function Button<TTag extends ElementType = typeof
|
||||
let buttonRef = useSyncRefs(
|
||||
internalButtonRef,
|
||||
ref,
|
||||
isWithinPanel ? null : 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<typeof OverlayRenderFeatures>,
|
||||
ref: Ref<HTMLDivElement>
|
||||
) {
|
||||
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<OverlayRenderPropArg>(() => ({ open: popoverState === PopoverStates.Open }), [
|
||||
popoverState,
|
||||
])
|
||||
let slot = useMemo<OverlayRenderPropArg>(
|
||||
() => ({ open: popoverState === PopoverStates.Open }),
|
||||
[popoverState]
|
||||
)
|
||||
let propsWeControl = {
|
||||
ref: overlayRef,
|
||||
id,
|
||||
@@ -580,11 +581,11 @@ let Panel = forwardRefWithAs(function Panel<TTag extends ElementType = typeof DE
|
||||
) {
|
||||
let { focus = false, ...passthroughProps } = props
|
||||
|
||||
let [state, dispatch] = usePopoverContext([Popover.name, Panel.name].join('.'))
|
||||
let { close } = usePopoverAPIContext([Popover.name, Panel.name].join('.'))
|
||||
let [state, dispatch] = usePopoverContext('Popover.Panel')
|
||||
let { close } = usePopoverAPIContext('Popover.Panel')
|
||||
|
||||
let internalPanelRef = useRef<HTMLDivElement | null>(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<TTag extends ElementType = typeof DE
|
||||
}, [focus, internalPanelRef, state.popoverState])
|
||||
|
||||
// Handle Tab / Shift+Tab focus positioning
|
||||
useWindowEvent('keydown', event => {
|
||||
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<TTag extends ElementType = typeof DE
|
||||
|
||||
let nextElements = elements
|
||||
.splice(buttonIdx + 1) // Elements after button
|
||||
.filter(element => !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<TTag extends ElementType = typeof DEFAULT_PANEL_TAG>(
|
||||
|
||||
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<TTag extends ElementType = typeof DEFAULT_PANEL_TAG>(
|
||||
|
||||
let registerPopover = useCallback(
|
||||
(registerbag: PopoverRegisterBag) => {
|
||||
setPopovers(existing => [...existing, registerbag])
|
||||
setPopovers((existing) => [...existing, registerbag])
|
||||
return () => unregisterPopover(registerbag)
|
||||
},
|
||||
[setPopovers, unregisterPopover]
|
||||
@@ -757,7 +758,7 @@ function Group<TTag extends ElementType = typeof DEFAULT_PANEL_TAG>(
|
||||
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)
|
||||
|
||||
@@ -82,10 +82,10 @@ it('should cleanup the Portal root when the last Portal is unmounted', async ()
|
||||
|
||||
return (
|
||||
<main id="parent">
|
||||
<button id="a" onClick={() => setRenderA(v => !v)}>
|
||||
<button id="a" onClick={() => setRenderA((v) => !v)}>
|
||||
Toggle A
|
||||
</button>
|
||||
<button id="b" onClick={() => setRenderB(v => !v)}>
|
||||
<button id="b" onClick={() => setRenderB((v) => !v)}>
|
||||
Toggle B
|
||||
</button>
|
||||
|
||||
@@ -151,21 +151,21 @@ it('should be possible to render multiple portals at the same time', async () =>
|
||||
|
||||
return (
|
||||
<main id="parent">
|
||||
<button id="a" onClick={() => setRenderA(v => !v)}>
|
||||
<button id="a" onClick={() => setRenderA((v) => !v)}>
|
||||
Toggle A
|
||||
</button>
|
||||
<button id="b" onClick={() => setRenderB(v => !v)}>
|
||||
<button id="b" onClick={() => setRenderB((v) => !v)}>
|
||||
Toggle B
|
||||
</button>
|
||||
<button id="c" onClick={() => setRenderC(v => !v)}>
|
||||
<button id="c" onClick={() => setRenderC((v) => !v)}>
|
||||
Toggle C
|
||||
</button>
|
||||
|
||||
<button
|
||||
id="double"
|
||||
onClick={() => {
|
||||
setRenderA(v => !v)
|
||||
setRenderB(v => !v)
|
||||
setRenderA((v) => !v)
|
||||
setRenderB((v) => !v)
|
||||
}}
|
||||
>
|
||||
Toggle A & B{' '}
|
||||
@@ -231,10 +231,10 @@ it('should be possible to tamper with the modal root and restore correctly', asy
|
||||
|
||||
return (
|
||||
<main id="parent">
|
||||
<button id="a" onClick={() => setRenderA(v => !v)}>
|
||||
<button id="a" onClick={() => setRenderA((v) => !v)}>
|
||||
Toggle A
|
||||
</button>
|
||||
<button id="b" onClick={() => setRenderB(v => !v)}>
|
||||
<button id="b" onClick={() => setRenderB((v) => !v)}>
|
||||
Toggle B
|
||||
</button>
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ describe('Rendering', () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<button onClick={() => setShowFirst(v => !v)}>Toggle</button>
|
||||
<button onClick={() => setShowFirst((v) => !v)}>Toggle</button>
|
||||
<RadioGroup value={active} onChange={setActive}>
|
||||
<RadioGroup.Label>Pizza Delivery</RadioGroup.Label>
|
||||
{showFirst && <RadioGroup.Option value="pickup">Pickup</RadioGroup.Option>}
|
||||
@@ -145,7 +145,7 @@ describe('Rendering', () => {
|
||||
let [disabled, setDisabled] = useState(true)
|
||||
return (
|
||||
<>
|
||||
<button onClick={() => setDisabled(v => !v)}>Toggle</button>
|
||||
<button onClick={() => setDisabled((v) => !v)}>Toggle</button>
|
||||
<RadioGroup value={undefined} onChange={changeFn} disabled={disabled}>
|
||||
<RadioGroup.Label>Pizza Delivery</RadioGroup.Label>
|
||||
<RadioGroup.Option value="pickup">Pickup</RadioGroup.Option>
|
||||
@@ -208,7 +208,7 @@ describe('Rendering', () => {
|
||||
let [disabled, setDisabled] = useState(true)
|
||||
return (
|
||||
<>
|
||||
<button onClick={() => setDisabled(v => !v)}>Toggle</button>
|
||||
<button onClick={() => setDisabled((v) => !v)}>Toggle</button>
|
||||
<RadioGroup value={undefined} onChange={changeFn}>
|
||||
<RadioGroup.Label>Pizza Delivery</RadioGroup.Label>
|
||||
<RadioGroup.Option value="pickup">Pickup</RadioGroup.Option>
|
||||
@@ -745,7 +745,7 @@ describe('Keyboard interactions', () => {
|
||||
<button>Before</button>
|
||||
<RadioGroup
|
||||
value={value}
|
||||
onChange={v => {
|
||||
onChange={(v) => {
|
||||
setValue(v)
|
||||
changeFn(v)
|
||||
}}
|
||||
@@ -815,7 +815,7 @@ describe('Mouse interactions', () => {
|
||||
<button>Before</button>
|
||||
<RadioGroup
|
||||
value={value}
|
||||
onChange={v => {
|
||||
onChange={(v) => {
|
||||
setValue(v)
|
||||
changeFn(v)
|
||||
}}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -214,7 +214,7 @@ describe('Keyboard interactions', () => {
|
||||
return (
|
||||
<Switch
|
||||
checked={state}
|
||||
onChange={value => {
|
||||
onChange={(value) => {
|
||||
setState(value)
|
||||
handleChange(value)
|
||||
}}
|
||||
@@ -297,7 +297,7 @@ describe('Mouse interactions', () => {
|
||||
return (
|
||||
<Switch
|
||||
checked={state}
|
||||
onChange={value => {
|
||||
onChange={(value) => {
|
||||
setState(value)
|
||||
handleChange(value)
|
||||
}}
|
||||
@@ -331,7 +331,7 @@ describe('Mouse interactions', () => {
|
||||
<Switch.Group>
|
||||
<Switch
|
||||
checked={state}
|
||||
onChange={value => {
|
||||
onChange={(value) => {
|
||||
setState(value)
|
||||
handleChange(value)
|
||||
}}
|
||||
@@ -373,7 +373,7 @@ describe('Mouse interactions', () => {
|
||||
<Switch.Group>
|
||||
<Switch
|
||||
checked={state}
|
||||
onChange={value => {
|
||||
onChange={(value) => {
|
||||
setState(value)
|
||||
handleChange(value)
|
||||
}}
|
||||
|
||||
@@ -81,7 +81,7 @@ describe('Rendering', () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<button onClick={() => setHide(v => !v)}>toggle</button>
|
||||
<button onClick={() => setHide((v) => !v)}>toggle</button>
|
||||
<Tab.Group>
|
||||
<Tab.List>
|
||||
<Tab>Tab 1</Tab>
|
||||
@@ -118,7 +118,7 @@ describe('Rendering', () => {
|
||||
it('should expose the `selectedIndex` on the `Tab.Group` component', async () => {
|
||||
render(
|
||||
<Tab.Group>
|
||||
{data => (
|
||||
{(data) => (
|
||||
<>
|
||||
<pre id="exposed">{JSON.stringify(data)}</pre>
|
||||
|
||||
@@ -153,7 +153,7 @@ describe('Rendering', () => {
|
||||
render(
|
||||
<Tab.Group>
|
||||
<Tab.List>
|
||||
{data => (
|
||||
{(data) => (
|
||||
<>
|
||||
<pre id="exposed">{JSON.stringify(data)}</pre>
|
||||
<Tab>Tab 1</Tab>
|
||||
@@ -192,7 +192,7 @@ describe('Rendering', () => {
|
||||
</Tab.List>
|
||||
|
||||
<Tab.Panels>
|
||||
{data => (
|
||||
{(data) => (
|
||||
<>
|
||||
<pre id="exposed">{JSON.stringify(data)}</pre>
|
||||
<Tab.Panel>Content 1</Tab.Panel>
|
||||
@@ -220,7 +220,7 @@ describe('Rendering', () => {
|
||||
<Tab.Group>
|
||||
<Tab.List>
|
||||
<Tab>
|
||||
{data => (
|
||||
{(data) => (
|
||||
<>
|
||||
<pre data-tab={0}>{JSON.stringify(data)}</pre>
|
||||
<span>Tab 1</span>
|
||||
@@ -228,7 +228,7 @@ describe('Rendering', () => {
|
||||
)}
|
||||
</Tab>
|
||||
<Tab>
|
||||
{data => (
|
||||
{(data) => (
|
||||
<>
|
||||
<pre data-tab={1}>{JSON.stringify(data)}</pre>
|
||||
<span>Tab 2</span>
|
||||
@@ -236,7 +236,7 @@ describe('Rendering', () => {
|
||||
)}
|
||||
</Tab>
|
||||
<Tab>
|
||||
{data => (
|
||||
{(data) => (
|
||||
<>
|
||||
<pre data-tab={2}>{JSON.stringify(data)}</pre>
|
||||
<span>Tab 3</span>
|
||||
@@ -287,7 +287,7 @@ describe('Rendering', () => {
|
||||
|
||||
<Tab.Panels>
|
||||
<Tab.Panel unmount={false}>
|
||||
{data => (
|
||||
{(data) => (
|
||||
<>
|
||||
<pre data-panel={0}>{JSON.stringify(data)}</pre>
|
||||
<span>Content 1</span>
|
||||
@@ -295,7 +295,7 @@ describe('Rendering', () => {
|
||||
)}
|
||||
</Tab.Panel>
|
||||
<Tab.Panel unmount={false}>
|
||||
{data => (
|
||||
{(data) => (
|
||||
<>
|
||||
<pre data-panel={1}>{JSON.stringify(data)}</pre>
|
||||
<span>Content 2</span>
|
||||
@@ -303,7 +303,7 @@ describe('Rendering', () => {
|
||||
)}
|
||||
</Tab.Panel>
|
||||
<Tab.Panel unmount={false}>
|
||||
{data => (
|
||||
{(data) => (
|
||||
<>
|
||||
<pre data-panel={2}>{JSON.stringify(data)}</pre>
|
||||
<span>Content 3</span>
|
||||
@@ -514,7 +514,7 @@ describe('Rendering', () => {
|
||||
<>
|
||||
<Tab.Group
|
||||
selectedIndex={selectedIndex}
|
||||
onChange={value => {
|
||||
onChange={(value) => {
|
||||
setSelectedIndex(value)
|
||||
handleChange(value)
|
||||
}}
|
||||
@@ -533,7 +533,7 @@ describe('Rendering', () => {
|
||||
</Tab.Group>
|
||||
|
||||
<button>after</button>
|
||||
<button onClick={() => setSelectedIndex(prev => prev + 1)}>setSelectedIndex</button>
|
||||
<button onClick={() => setSelectedIndex((prev) => prev + 1)}>setSelectedIndex</button>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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<TTag extends ElementType = typeof DEFAULT_TABS_TAG>(
|
||||
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<TTag extends ElementType = typeof DEFAULT_TABS_TAG>(
|
||||
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<TTag extends ElementType = typeof DEFAULT_LIST_TAG>(
|
||||
props: Props<TTag, ListRenderPropArg, ListPropsWeControl> & {}
|
||||
) {
|
||||
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<TTag extends ElementType = typeof DEFAULT_TAB_TAG>(
|
||||
) {
|
||||
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<HTMLElement>(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<TTag extends ElementType = typeof DEFAULT_TAB_TAG>(
|
||||
|
||||
let handleKeyDown = useCallback(
|
||||
(event: ReactKeyboardEvent<HTMLElement>) => {
|
||||
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<TTag extends ElementType = typeof DEFAULT_PANELS_TAG>(
|
||||
props: Props<TTag, PanelsRenderPropArg>
|
||||
) {
|
||||
let [{ selectedIndex }] = useTabsContext([Tab.name, Panels.name].join('.'))
|
||||
let [{ selectedIndex }] = useTabsContext('Tab.Panels')
|
||||
|
||||
let slot = useMemo(() => ({ selectedIndex }), [selectedIndex])
|
||||
|
||||
@@ -405,13 +403,11 @@ function Panel<TTag extends ElementType = typeof DEFAULT_PANEL_TAG>(
|
||||
props: Props<TTag, PanelRenderPropArg, PanelPropsWeControl> &
|
||||
PropsForFeatures<typeof PanelRenderFeatures>
|
||||
) {
|
||||
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<HTMLElement>(null)
|
||||
let panelRef = useSyncRefs(internalPanelRef, element => {
|
||||
let panelRef = useSyncRefs(internalPanelRef, (element) => {
|
||||
if (!element) return
|
||||
dispatch({ type: ActionTypes.ForceRerender })
|
||||
})
|
||||
|
||||
@@ -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.
|
||||
<Transition>
|
||||
<div className="hello">Children</div>
|
||||
</Transition>
|
||||
@@ -445,7 +443,7 @@ describe('Transitions', () => {
|
||||
<span>Hello!</span>
|
||||
</Transition>
|
||||
|
||||
<button data-testid="toggle" onClick={() => setShow(v => !v)}>
|
||||
<button data-testid="toggle" onClick={() => setShow((v) => !v)}>
|
||||
Toggle
|
||||
</button>
|
||||
</>
|
||||
@@ -488,14 +486,15 @@ describe('Transitions', () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<style>{`.enter { transition-duration: ${enterDuration /
|
||||
1000}s; } .from { opacity: 0%; } .to { opacity: 100%; }`}</style>
|
||||
<style>{`.enter { transition-duration: ${
|
||||
enterDuration / 1000
|
||||
}s; } .from { opacity: 0%; } .to { opacity: 100%; }`}</style>
|
||||
|
||||
<Transition show={show} enter="enter" enterFrom="from" enterTo="to">
|
||||
<span>Hello!</span>
|
||||
</Transition>
|
||||
|
||||
<button data-testid="toggle" onClick={() => setShow(v => !v)}>
|
||||
<button data-testid="toggle" onClick={() => setShow((v) => !v)}>
|
||||
Toggle
|
||||
</button>
|
||||
</>
|
||||
@@ -538,14 +537,15 @@ describe('Transitions', () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<style>{`.enter { transition-duration: ${enterDuration /
|
||||
1000}s; } .from { opacity: 0%; } .to { opacity: 100%; }`}</style>
|
||||
<style>{`.enter { transition-duration: ${
|
||||
enterDuration / 1000
|
||||
}s; } .from { opacity: 0%; } .to { opacity: 100%; }`}</style>
|
||||
|
||||
<Transition show={show} unmount={false} enter="enter" enterFrom="from" enterTo="to">
|
||||
<span>Hello!</span>
|
||||
</Transition>
|
||||
|
||||
<button data-testid="toggle" onClick={() => setShow(v => !v)}>
|
||||
<button data-testid="toggle" onClick={() => setShow((v) => !v)}>
|
||||
Toggle
|
||||
</button>
|
||||
</>
|
||||
@@ -591,7 +591,7 @@ describe('Transitions', () => {
|
||||
<span>Hello!</span>
|
||||
</Transition>
|
||||
|
||||
<button data-testid="toggle" onClick={() => setShow(v => !v)}>
|
||||
<button data-testid="toggle" onClick={() => setShow((v) => !v)}>
|
||||
Toggle
|
||||
</button>
|
||||
</>
|
||||
@@ -642,7 +642,7 @@ describe('Transitions', () => {
|
||||
<span>Hello!</span>
|
||||
</Transition>
|
||||
|
||||
<button data-testid="toggle" onClick={() => setShow(v => !v)}>
|
||||
<button data-testid="toggle" onClick={() => setShow((v) => !v)}>
|
||||
Toggle
|
||||
</button>
|
||||
</>
|
||||
@@ -696,7 +696,7 @@ describe('Transitions', () => {
|
||||
<span>Hello!</span>
|
||||
</Transition>
|
||||
|
||||
<button data-testid="toggle" onClick={() => setShow(v => !v)}>
|
||||
<button data-testid="toggle" onClick={() => setShow((v) => !v)}>
|
||||
Toggle
|
||||
</button>
|
||||
</>
|
||||
@@ -757,7 +757,7 @@ describe('Transitions', () => {
|
||||
<span>Hello!</span>
|
||||
</Transition>
|
||||
|
||||
<button data-testid="toggle" onClick={() => setShow(v => !v)}>
|
||||
<button data-testid="toggle" onClick={() => setShow((v) => !v)}>
|
||||
Toggle
|
||||
</button>
|
||||
</>
|
||||
@@ -843,7 +843,7 @@ describe('Transitions', () => {
|
||||
<span>Hello!</span>
|
||||
</Transition>
|
||||
|
||||
<button data-testid="toggle" onClick={() => setShow(v => !v)}>
|
||||
<button data-testid="toggle" onClick={() => setShow((v) => !v)}>
|
||||
Toggle
|
||||
</button>
|
||||
</>
|
||||
@@ -943,7 +943,7 @@ describe('Transitions', () => {
|
||||
</Transition.Child>
|
||||
</Transition>
|
||||
|
||||
<button data-testid="toggle" onClick={() => setShow(v => !v)}>
|
||||
<button data-testid="toggle" onClick={() => setShow((v) => !v)}>
|
||||
Toggle
|
||||
</button>
|
||||
</>
|
||||
@@ -1027,7 +1027,7 @@ describe('Transitions', () => {
|
||||
</Transition.Child>
|
||||
</Transition>
|
||||
|
||||
<button data-testid="toggle" onClick={() => setShow(v => !v)}>
|
||||
<button data-testid="toggle" onClick={() => setShow((v) => !v)}>
|
||||
Toggle
|
||||
</button>
|
||||
</>
|
||||
@@ -1138,7 +1138,7 @@ describe('Events', () => {
|
||||
<span>Hello!</span>
|
||||
</Transition>
|
||||
|
||||
<button data-testid="toggle" onClick={() => setShow(v => !v)}>
|
||||
<button data-testid="toggle" onClick={() => setShow((v) => !v)}>
|
||||
Toggle
|
||||
</button>
|
||||
</>
|
||||
|
||||
@@ -28,9 +28,10 @@ import { useServerHandoffComplete } from '../../hooks/use-server-handoff-complet
|
||||
type ID = ReturnType<typeof useId>
|
||||
|
||||
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<TTag extends ElementType = typeof DEFAULT_TRANSITION_CH
|
||||
if (!show) events.current.beforeLeave()
|
||||
|
||||
return show
|
||||
? 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()
|
||||
? 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<TTag extends ElementType = typeof DEFAULT_TRANSITION_
|
||||
})
|
||||
}
|
||||
|
||||
if (![true, false].includes((show as unknown) as boolean)) {
|
||||
if (![true, false].includes(show as unknown as boolean)) {
|
||||
throw new Error('A <Transition /> is used but it is missing a `show={true | false}` prop.')
|
||||
}
|
||||
|
||||
|
||||
@@ -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('<div></div>')
|
||||
@@ -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')
|
||||
})
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -17,7 +17,7 @@ it('should be possible to inert other elements', async () => {
|
||||
|
||||
return (
|
||||
<div ref={ref} id="main">
|
||||
<button onClick={() => setEnabled(v => !v)}>toggle</button>
|
||||
<button onClick={() => setEnabled((v) => !v)}>toggle</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -61,7 +61,7 @@ it('should restore inert elements, when all useInertOthers calls are disabled',
|
||||
|
||||
return (
|
||||
<div ref={ref} id={id}>
|
||||
<button onClick={() => setEnabled(v => !v)}>{toggle}</button>
|
||||
<button onClick={() => setEnabled((v) => !v)}>{toggle}</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -136,7 +136,7 @@ it('should restore inert elements, when all useInertOthers calls are disabled (i
|
||||
return (
|
||||
<div id={`parent-${id}`}>
|
||||
<div ref={ref} id={id}>
|
||||
<button onClick={() => setEnabled(v => !v)}>{toggle}</button>
|
||||
<button onClick={() => setEnabled((v) => !v)}>{toggle}</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
@@ -221,7 +221,7 @@ it('should handle inert others correctly when 2 useInertOthers are used in a sha
|
||||
|
||||
return (
|
||||
<div ref={ref} id={id}>
|
||||
<button onClick={() => setEnabled(v => !v)}>{toggle}</button>
|
||||
<button onClick={() => setEnabled((v) => !v)}>{toggle}</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ export function useInertOthers<TElement extends HTMLElement>(
|
||||
}
|
||||
|
||||
// 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<TElement extends HTMLElement>(
|
||||
// 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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1256,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
|
||||
}
|
||||
|
||||
@@ -1612,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')
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ export function shift(event: Partial<KeyboardEvent>) {
|
||||
}
|
||||
|
||||
export function word(input: string): Partial<KeyboardEvent>[] {
|
||||
let result = input.split('').map(key => ({ key }))
|
||||
let result = input.split('').map((key) => ({ key }))
|
||||
|
||||
d.enqueue(() => {
|
||||
let element = document.activeElement
|
||||
@@ -152,7 +152,7 @@ export async function type(events: Partial<KeyboardEvent>[], 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,
|
||||
@@ -344,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(',')
|
||||
|
||||
|
||||
@@ -5,10 +5,10 @@ type FunctionPropertyNames<T> = {
|
||||
|
||||
export function suppressConsoleLogs<T extends unknown[]>(
|
||||
cb: (...args: T) => unknown,
|
||||
type: FunctionPropertyNames<typeof global.console> = 'error'
|
||||
type: FunctionPropertyNames<typeof globalThis.console> = '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<unknown>((resolve, reject) => {
|
||||
Promise.resolve(cb(...args)).then(resolve, reject)
|
||||
|
||||
@@ -40,7 +40,7 @@ export function calculateActiveIndex<TItem>(
|
||||
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<TItem>(
|
||||
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
|
||||
|
||||
@@ -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(',')
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ export function match<TValue extends string | number = string, TReturnValue = un
|
||||
`Tried to handle "${value}" but there is no handler defined. Only defined handlers are: ${Object.keys(
|
||||
lookup
|
||||
)
|
||||
.map(key => `"${key}"`)
|
||||
.map((key) => `"${key}"`)
|
||||
.join(', ')}.`
|
||||
)
|
||||
if (Error.captureStackTrace) Error.captureStackTrace(error, match)
|
||||
|
||||
@@ -45,7 +45,7 @@ describe('Default functionality', () => {
|
||||
|
||||
testRender(
|
||||
<Dummy>
|
||||
{data => {
|
||||
{(data) => {
|
||||
expect(data).toBe(slot)
|
||||
|
||||
return <span>Contents</span>
|
||||
|
||||
@@ -102,10 +102,12 @@ function _render<TTag extends ElementType, TSlot>(
|
||||
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 `<HeadlessUIComponent as={MyComponent} refName="innerRef" />`
|
||||
let refRelatedProps = props.ref !== undefined ? { [refName]: props.ref } : {}
|
||||
@@ -132,7 +134,7 @@ function _render<TTag extends ElementType, TSlot>(
|
||||
`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<TTag extends ElementType, TSlot>(
|
||||
'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<T extends { name: string; displayName?: string }>(
|
||||
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,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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?"]
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
|
||||
"compilerOptions": {
|
||||
"jsx": "react"
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
},
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
export {}
|
||||
|
||||
declare global {
|
||||
namespace jest {
|
||||
interface Matchers<R> {
|
||||
toBeWithinRenderFrame(actual: number): R
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
module.exports = {
|
||||
rules: {
|
||||
'react-hooks/rules-of-hooks': 'off',
|
||||
'react-hooks/exhaustive-deps': 'off',
|
||||
},
|
||||
}
|
||||
@@ -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')
|
||||
}
|
||||
@@ -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"
|
||||
@@ -27,14 +36,16 @@
|
||||
"build": "../../scripts/build.sh",
|
||||
"watch": "../../scripts/watch.sh",
|
||||
"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"
|
||||
},
|
||||
"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.27"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
module.exports = require('../../postcss.config.js')
|
||||
@@ -66,7 +66,7 @@ beforeAll(() => {
|
||||
afterAll(() => jest.restoreAllMocks())
|
||||
|
||||
function nextFrame() {
|
||||
return new Promise<void>(resolve => {
|
||||
return new Promise<void>((resolve) => {
|
||||
requestAnimationFrame(() => {
|
||||
requestAnimationFrame(() => {
|
||||
resolve()
|
||||
@@ -95,9 +95,9 @@ function renderTemplate(input: string | Partial<DefineComponent>) {
|
||||
|
||||
return render(
|
||||
defineComponent(
|
||||
(Object.assign({}, input, {
|
||||
Object.assign({}, input, {
|
||||
components: { ...defaultComponents, ...input.components },
|
||||
}) as unknown) as DefineComponent
|
||||
}) as Parameters<typeof defineComponent>[0]
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -491,9 +491,7 @@ describe('Rendering', () => {
|
||||
template: html`
|
||||
<Combobox v-model="value">
|
||||
<ComboboxInput />
|
||||
<ComboboxButton type="submit">
|
||||
Trigger
|
||||
</ComboboxButton>
|
||||
<ComboboxButton type="submit"> Trigger </ComboboxButton>
|
||||
</Combobox>
|
||||
`,
|
||||
setup: () => ({ value: ref(null) }),
|
||||
@@ -506,16 +504,14 @@ describe('Rendering', () => {
|
||||
'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 }),
|
||||
setup: (props) => () => h('button', { ...props }),
|
||||
})
|
||||
|
||||
renderTemplate({
|
||||
template: html`
|
||||
<Combobox v-model="value">
|
||||
<ComboboxInput />
|
||||
<ComboboxButton :as="CustomButton">
|
||||
Trigger
|
||||
</ComboboxButton>
|
||||
<ComboboxButton :as="CustomButton"> Trigger </ComboboxButton>
|
||||
</Combobox>
|
||||
`,
|
||||
setup: () => ({
|
||||
@@ -535,9 +531,7 @@ describe('Rendering', () => {
|
||||
template: html`
|
||||
<Combobox v-model="value">
|
||||
<ComboboxInput />
|
||||
<ComboboxButton as="div">
|
||||
Trigger
|
||||
</ComboboxButton>
|
||||
<ComboboxButton as="div"> Trigger </ComboboxButton>
|
||||
</Combobox>
|
||||
`,
|
||||
setup: () => ({ value: ref(null) }),
|
||||
@@ -550,16 +544,14 @@ describe('Rendering', () => {
|
||||
'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),
|
||||
setup: (props) => () => h('div', props),
|
||||
})
|
||||
|
||||
renderTemplate({
|
||||
template: html`
|
||||
<Combobox v-model="value">
|
||||
<ComboboxInput />
|
||||
<ComboboxButton :as="CustomButton">
|
||||
Trigger
|
||||
</ComboboxButton>
|
||||
<ComboboxButton :as="CustomButton"> Trigger </ComboboxButton>
|
||||
</Combobox>
|
||||
`,
|
||||
setup: () => ({
|
||||
@@ -765,15 +757,9 @@ describe('Rendering composition', () => {
|
||||
<ComboboxInput />
|
||||
<ComboboxButton>Trigger</ComboboxButton>
|
||||
<ComboboxOptions>
|
||||
<ComboboxOption as="button" value="a">
|
||||
Option A
|
||||
</ComboboxOption>
|
||||
<ComboboxOption as="button" value="b">
|
||||
Option B
|
||||
</ComboboxOption>
|
||||
<ComboboxOption as="button" value="c">
|
||||
Option C
|
||||
</ComboboxOption>
|
||||
<ComboboxOption as="button" value="a"> Option A </ComboboxOption>
|
||||
<ComboboxOption as="button" value="b"> Option B </ComboboxOption>
|
||||
<ComboboxOption as="button" value="c"> Option C </ComboboxOption>
|
||||
</ComboboxOptions>
|
||||
</Combobox>
|
||||
`,
|
||||
@@ -790,7 +776,7 @@ describe('Rendering composition', () => {
|
||||
await click(getComboboxButton())
|
||||
|
||||
// Verify options are buttons now
|
||||
getComboboxOptions().forEach(option => assertComboboxOption(option, { tag: 'button' }))
|
||||
getComboboxOptions().forEach((option) => assertComboboxOption(option, { tag: 'button' }))
|
||||
})
|
||||
)
|
||||
})
|
||||
@@ -823,9 +809,7 @@ describe('Composition', () => {
|
||||
<ComboboxInput />
|
||||
<ComboboxButton>Trigger</ComboboxButton>
|
||||
<OpenClosedWrite :open="true">
|
||||
<ComboboxOptions v-slot="data">
|
||||
{{JSON.stringify(data)}}
|
||||
</ComboboxOptions>
|
||||
<ComboboxOptions v-slot="data"> {{JSON.stringify(data)}} </ComboboxOptions>
|
||||
</OpenClosedWrite>
|
||||
</Combobox>
|
||||
`,
|
||||
@@ -854,9 +838,7 @@ describe('Composition', () => {
|
||||
<ComboboxInput />
|
||||
<ComboboxButton>Trigger</ComboboxButton>
|
||||
<OpenClosedWrite :open="false">
|
||||
<ComboboxOptions v-slot="data">
|
||||
{{JSON.stringify(data)}}
|
||||
</ComboboxOptions>
|
||||
<ComboboxOptions v-slot="data"> {{JSON.stringify(data)}} </ComboboxOptions>
|
||||
</OpenClosedWrite>
|
||||
</Combobox>
|
||||
`,
|
||||
@@ -966,7 +948,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option, { selected: false }))
|
||||
options.forEach((option) => assertComboboxOption(option, { selected: false }))
|
||||
|
||||
assertNoActiveComboboxOption()
|
||||
assertNoSelectedComboboxOption()
|
||||
@@ -1274,7 +1256,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
assertNoActiveComboboxOption()
|
||||
})
|
||||
)
|
||||
@@ -1408,15 +1390,9 @@ describe('Keyboard interactions', () => {
|
||||
<ComboboxInput />
|
||||
<ComboboxButton>Trigger</ComboboxButton>
|
||||
<ComboboxOptions>
|
||||
<ComboboxOption disabled value="a">
|
||||
Option A
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="b">
|
||||
Option B
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="c">
|
||||
Option C
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="a"> Option A </ComboboxOption>
|
||||
<ComboboxOption disabled value="b"> Option B </ComboboxOption>
|
||||
<ComboboxOption disabled value="c"> Option C </ComboboxOption>
|
||||
</ComboboxOptions>
|
||||
</Combobox>
|
||||
`,
|
||||
@@ -1533,7 +1509,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
|
||||
// Verify that the first combobox option is active
|
||||
assertNoActiveComboboxOption()
|
||||
@@ -1701,7 +1677,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
|
||||
// Verify that the first combobox option is active
|
||||
assertNoActiveComboboxOption()
|
||||
@@ -1869,7 +1845,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
|
||||
// ! ALERT: The LAST option should now be active
|
||||
assertActiveComboboxOption(options[2])
|
||||
@@ -2002,12 +1978,8 @@ describe('Keyboard interactions', () => {
|
||||
<ComboboxButton>Trigger</ComboboxButton>
|
||||
<ComboboxOptions>
|
||||
<ComboboxOption value="a">Option A</ComboboxOption>
|
||||
<ComboboxOption disabled value="b">
|
||||
Option B
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="c">
|
||||
Option C
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="b"> Option B </ComboboxOption>
|
||||
<ComboboxOption disabled value="c"> Option C </ComboboxOption>
|
||||
</ComboboxOptions>
|
||||
</Combobox>
|
||||
`,
|
||||
@@ -2029,7 +2001,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
assertActiveComboboxOption(options[0])
|
||||
})
|
||||
)
|
||||
@@ -2079,7 +2051,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
|
||||
// ! ALERT: The LAST option should now be active
|
||||
assertActiveComboboxOption(options[2])
|
||||
@@ -2213,12 +2185,8 @@ describe('Keyboard interactions', () => {
|
||||
<ComboboxButton>Trigger</ComboboxButton>
|
||||
<ComboboxOptions>
|
||||
<ComboboxOption value="a">Option A</ComboboxOption>
|
||||
<ComboboxOption disabled value="b">
|
||||
Option B
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="c">
|
||||
Option C
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="b"> Option B </ComboboxOption>
|
||||
<ComboboxOption disabled value="c"> Option C </ComboboxOption>
|
||||
</ComboboxOptions>
|
||||
</Combobox>
|
||||
`,
|
||||
@@ -2240,7 +2208,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
assertActiveComboboxOption(options[0])
|
||||
})
|
||||
)
|
||||
@@ -2496,7 +2464,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
|
||||
// Verify that the first combobox option is active
|
||||
assertNoActiveComboboxOption()
|
||||
@@ -2649,7 +2617,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
assertNoActiveComboboxOption()
|
||||
|
||||
// We should be able to go down once
|
||||
@@ -2679,9 +2647,7 @@ describe('Keyboard interactions', () => {
|
||||
<ComboboxInput />
|
||||
<ComboboxButton>Trigger</ComboboxButton>
|
||||
<ComboboxOptions>
|
||||
<ComboboxOption disabled value="a">
|
||||
Option A
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="a"> Option A </ComboboxOption>
|
||||
<ComboboxOption value="b">Option B</ComboboxOption>
|
||||
<ComboboxOption value="c">Option C</ComboboxOption>
|
||||
</ComboboxOptions>
|
||||
@@ -2702,7 +2668,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
assertNoActiveComboboxOption()
|
||||
|
||||
// We should be able to go down once
|
||||
@@ -2720,12 +2686,8 @@ describe('Keyboard interactions', () => {
|
||||
<ComboboxInput />
|
||||
<ComboboxButton>Trigger</ComboboxButton>
|
||||
<ComboboxOptions>
|
||||
<ComboboxOption disabled value="a">
|
||||
Option A
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="b">
|
||||
Option B
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="a"> Option A </ComboboxOption>
|
||||
<ComboboxOption disabled value="b"> Option B </ComboboxOption>
|
||||
<ComboboxOption value="c">Option C</ComboboxOption>
|
||||
</ComboboxOptions>
|
||||
</Combobox>
|
||||
@@ -2745,7 +2707,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
assertNoActiveComboboxOption()
|
||||
|
||||
// Open combobox
|
||||
@@ -2799,7 +2761,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
|
||||
// Verify that the first combobox option is active
|
||||
assertNoActiveComboboxOption()
|
||||
@@ -2968,7 +2930,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
assertNoActiveComboboxOption()
|
||||
|
||||
// We should be able to go down once
|
||||
@@ -2998,9 +2960,7 @@ describe('Keyboard interactions', () => {
|
||||
<ComboboxInput />
|
||||
<ComboboxButton>Trigger</ComboboxButton>
|
||||
<ComboboxOptions>
|
||||
<ComboboxOption disabled value="a">
|
||||
Option A
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="a"> Option A </ComboboxOption>
|
||||
<ComboboxOption value="b">Option B</ComboboxOption>
|
||||
<ComboboxOption value="c">Option C</ComboboxOption>
|
||||
</ComboboxOptions>
|
||||
@@ -3021,7 +2981,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
assertNoActiveComboboxOption()
|
||||
|
||||
// We should be able to go down once
|
||||
@@ -3039,12 +2999,8 @@ describe('Keyboard interactions', () => {
|
||||
<ComboboxInput />
|
||||
<ComboboxButton>Trigger</ComboboxButton>
|
||||
<ComboboxOptions>
|
||||
<ComboboxOption disabled value="a">
|
||||
Option A
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="b">
|
||||
Option B
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="a"> Option A </ComboboxOption>
|
||||
<ComboboxOption disabled value="b"> Option B </ComboboxOption>
|
||||
<ComboboxOption value="c">Option C</ComboboxOption>
|
||||
</ComboboxOptions>
|
||||
</Combobox>
|
||||
@@ -3064,7 +3020,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
assertNoActiveComboboxOption()
|
||||
|
||||
// Open combobox
|
||||
@@ -3117,7 +3073,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
|
||||
// ! ALERT: The LAST option should now be active
|
||||
assertActiveComboboxOption(options[2])
|
||||
@@ -3250,12 +3206,8 @@ describe('Keyboard interactions', () => {
|
||||
<ComboboxButton>Trigger</ComboboxButton>
|
||||
<ComboboxOptions>
|
||||
<ComboboxOption value="a">Option A</ComboboxOption>
|
||||
<ComboboxOption disabled value="b">
|
||||
Option B
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="c">
|
||||
Option C
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="b"> Option B </ComboboxOption>
|
||||
<ComboboxOption disabled value="c"> Option C </ComboboxOption>
|
||||
</ComboboxOptions>
|
||||
</Combobox>
|
||||
`,
|
||||
@@ -3277,7 +3229,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
assertActiveComboboxOption(options[0])
|
||||
})
|
||||
)
|
||||
@@ -3291,12 +3243,8 @@ describe('Keyboard interactions', () => {
|
||||
<ComboboxInput />
|
||||
<ComboboxButton>Trigger</ComboboxButton>
|
||||
<ComboboxOptions>
|
||||
<ComboboxOption disabled value="a">
|
||||
Option A
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="b">
|
||||
Option B
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="a"> Option A </ComboboxOption>
|
||||
<ComboboxOption disabled value="b"> Option B </ComboboxOption>
|
||||
<ComboboxOption value="c">Option C</ComboboxOption>
|
||||
</ComboboxOptions>
|
||||
</Combobox>
|
||||
@@ -3316,7 +3264,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
assertNoActiveComboboxOption()
|
||||
|
||||
// Going up or down should select the single available option
|
||||
@@ -3374,7 +3322,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
assertActiveComboboxOption(options[2])
|
||||
|
||||
// We should be able to go down once
|
||||
@@ -3436,7 +3384,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
|
||||
// ! ALERT: The LAST option should now be active
|
||||
assertActiveComboboxOption(options[2])
|
||||
@@ -3570,12 +3518,8 @@ describe('Keyboard interactions', () => {
|
||||
<ComboboxButton>Trigger</ComboboxButton>
|
||||
<ComboboxOptions>
|
||||
<ComboboxOption value="a">Option A</ComboboxOption>
|
||||
<ComboboxOption disabled value="b">
|
||||
Option B
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="c">
|
||||
Option C
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="b"> Option B </ComboboxOption>
|
||||
<ComboboxOption disabled value="c"> Option C </ComboboxOption>
|
||||
</ComboboxOptions>
|
||||
</Combobox>
|
||||
`,
|
||||
@@ -3597,7 +3541,7 @@ describe('Keyboard interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
assertActiveComboboxOption(options[0])
|
||||
})
|
||||
)
|
||||
@@ -3647,12 +3591,8 @@ describe('Keyboard interactions', () => {
|
||||
<ComboboxOptions>
|
||||
<ComboboxOption value="a">Option A</ComboboxOption>
|
||||
<ComboboxOption value="b">Option B</ComboboxOption>
|
||||
<ComboboxOption disabled value="c">
|
||||
Option C
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="d">
|
||||
Option D
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="c"> Option C </ComboboxOption>
|
||||
<ComboboxOption disabled value="d"> Option D </ComboboxOption>
|
||||
</ComboboxOptions>
|
||||
</Combobox>
|
||||
`,
|
||||
@@ -3683,15 +3623,9 @@ describe('Keyboard interactions', () => {
|
||||
<ComboboxButton>Trigger</ComboboxButton>
|
||||
<ComboboxOptions>
|
||||
<ComboboxOption value="a">Option A</ComboboxOption>
|
||||
<ComboboxOption disabled value="b">
|
||||
Option B
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="c">
|
||||
Option C
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="d">
|
||||
Option D
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="b"> Option B </ComboboxOption>
|
||||
<ComboboxOption disabled value="c"> Option C </ComboboxOption>
|
||||
<ComboboxOption disabled value="d"> Option D </ComboboxOption>
|
||||
</ComboboxOptions>
|
||||
</Combobox>
|
||||
`,
|
||||
@@ -3721,18 +3655,10 @@ describe('Keyboard interactions', () => {
|
||||
<ComboboxInput />
|
||||
<ComboboxButton>Trigger</ComboboxButton>
|
||||
<ComboboxOptions>
|
||||
<ComboboxOption disabled value="a">
|
||||
Option A
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="b">
|
||||
Option B
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="c">
|
||||
Option C
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="d">
|
||||
Option D
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="a"> Option A </ComboboxOption>
|
||||
<ComboboxOption disabled value="b"> Option B </ComboboxOption>
|
||||
<ComboboxOption disabled value="c"> Option C </ComboboxOption>
|
||||
<ComboboxOption disabled value="d"> Option D </ComboboxOption>
|
||||
</ComboboxOptions>
|
||||
</Combobox>
|
||||
`,
|
||||
@@ -3797,12 +3723,8 @@ describe('Keyboard interactions', () => {
|
||||
<ComboboxOptions>
|
||||
<ComboboxOption value="a">Option A</ComboboxOption>
|
||||
<ComboboxOption value="b">Option B</ComboboxOption>
|
||||
<ComboboxOption disabled value="c">
|
||||
Option C
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="d">
|
||||
Option D
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="c"> Option C </ComboboxOption>
|
||||
<ComboboxOption disabled value="d"> Option D </ComboboxOption>
|
||||
</ComboboxOptions>
|
||||
</Combobox>
|
||||
`,
|
||||
@@ -3836,15 +3758,9 @@ describe('Keyboard interactions', () => {
|
||||
<ComboboxButton>Trigger</ComboboxButton>
|
||||
<ComboboxOptions>
|
||||
<ComboboxOption value="a">Option A</ComboboxOption>
|
||||
<ComboboxOption disabled value="b">
|
||||
Option B
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="c">
|
||||
Option C
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="d">
|
||||
Option D
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="b"> Option B </ComboboxOption>
|
||||
<ComboboxOption disabled value="c"> Option C </ComboboxOption>
|
||||
<ComboboxOption disabled value="d"> Option D </ComboboxOption>
|
||||
</ComboboxOptions>
|
||||
</Combobox>
|
||||
`,
|
||||
@@ -3874,18 +3790,10 @@ describe('Keyboard interactions', () => {
|
||||
<ComboboxInput />
|
||||
<ComboboxButton>Trigger</ComboboxButton>
|
||||
<ComboboxOptions>
|
||||
<ComboboxOption disabled value="a">
|
||||
Option A
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="b">
|
||||
Option B
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="c">
|
||||
Option C
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="d">
|
||||
Option D
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="a"> Option A </ComboboxOption>
|
||||
<ComboboxOption disabled value="b"> Option B </ComboboxOption>
|
||||
<ComboboxOption disabled value="c"> Option C </ComboboxOption>
|
||||
<ComboboxOption disabled value="d"> Option D </ComboboxOption>
|
||||
</ComboboxOptions>
|
||||
</Combobox>
|
||||
`,
|
||||
@@ -3951,12 +3859,8 @@ describe('Keyboard interactions', () => {
|
||||
<ComboboxInput />
|
||||
<ComboboxButton>Trigger</ComboboxButton>
|
||||
<ComboboxOptions>
|
||||
<ComboboxOption disabled value="a">
|
||||
Option A
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="b">
|
||||
Option B
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="a"> Option A </ComboboxOption>
|
||||
<ComboboxOption disabled value="b"> Option B </ComboboxOption>
|
||||
<ComboboxOption value="c">Option C</ComboboxOption>
|
||||
<ComboboxOption value="d">Option D</ComboboxOption>
|
||||
</ComboboxOptions>
|
||||
@@ -3990,15 +3894,9 @@ describe('Keyboard interactions', () => {
|
||||
<ComboboxInput />
|
||||
<ComboboxButton>Trigger</ComboboxButton>
|
||||
<ComboboxOptions>
|
||||
<ComboboxOption disabled value="a">
|
||||
Option A
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="b">
|
||||
Option B
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="c">
|
||||
Option C
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="a"> Option A </ComboboxOption>
|
||||
<ComboboxOption disabled value="b"> Option B </ComboboxOption>
|
||||
<ComboboxOption disabled value="c"> Option C </ComboboxOption>
|
||||
<ComboboxOption value="d">Option D</ComboboxOption>
|
||||
</ComboboxOptions>
|
||||
</Combobox>
|
||||
@@ -4029,18 +3927,10 @@ describe('Keyboard interactions', () => {
|
||||
<ComboboxInput />
|
||||
<ComboboxButton>Trigger</ComboboxButton>
|
||||
<ComboboxOptions>
|
||||
<ComboboxOption disabled value="a">
|
||||
Option A
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="b">
|
||||
Option B
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="c">
|
||||
Option C
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="d">
|
||||
Option D
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="a"> Option A </ComboboxOption>
|
||||
<ComboboxOption disabled value="b"> Option B </ComboboxOption>
|
||||
<ComboboxOption disabled value="c"> Option C </ComboboxOption>
|
||||
<ComboboxOption disabled value="d"> Option D </ComboboxOption>
|
||||
</ComboboxOptions>
|
||||
</Combobox>
|
||||
`,
|
||||
@@ -4106,12 +3996,8 @@ describe('Keyboard interactions', () => {
|
||||
<ComboboxInput />
|
||||
<ComboboxButton>Trigger</ComboboxButton>
|
||||
<ComboboxOptions>
|
||||
<ComboboxOption disabled value="a">
|
||||
Option A
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="b">
|
||||
Option B
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="a"> Option A </ComboboxOption>
|
||||
<ComboboxOption disabled value="b"> Option B </ComboboxOption>
|
||||
<ComboboxOption value="c">Option C</ComboboxOption>
|
||||
<ComboboxOption value="d">Option D</ComboboxOption>
|
||||
</ComboboxOptions>
|
||||
@@ -4145,15 +4031,9 @@ describe('Keyboard interactions', () => {
|
||||
<ComboboxInput />
|
||||
<ComboboxButton>Trigger</ComboboxButton>
|
||||
<ComboboxOptions>
|
||||
<ComboboxOption disabled value="a">
|
||||
Option A
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="b">
|
||||
Option B
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="c">
|
||||
Option C
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="a"> Option A </ComboboxOption>
|
||||
<ComboboxOption disabled value="b"> Option B </ComboboxOption>
|
||||
<ComboboxOption disabled value="c"> Option C </ComboboxOption>
|
||||
<ComboboxOption value="d">Option D</ComboboxOption>
|
||||
</ComboboxOptions>
|
||||
</Combobox>
|
||||
@@ -4184,18 +4064,10 @@ describe('Keyboard interactions', () => {
|
||||
<ComboboxInput />
|
||||
<ComboboxButton>Trigger</ComboboxButton>
|
||||
<ComboboxOptions>
|
||||
<ComboboxOption disabled value="a">
|
||||
Option A
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="b">
|
||||
Option B
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="c">
|
||||
Option C
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="d">
|
||||
Option D
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="a"> Option A </ComboboxOption>
|
||||
<ComboboxOption disabled value="b"> Option B </ComboboxOption>
|
||||
<ComboboxOption disabled value="c"> Option C </ComboboxOption>
|
||||
<ComboboxOption disabled value="d"> Option D </ComboboxOption>
|
||||
</ComboboxOptions>
|
||||
</Combobox>
|
||||
`,
|
||||
@@ -4250,7 +4122,7 @@ describe('Keyboard interactions', () => {
|
||||
let filteredPeople = computed(() => {
|
||||
return query.value === ''
|
||||
? props.people
|
||||
: props.people.filter(person =>
|
||||
: props.people.filter((person) =>
|
||||
person.name.toLowerCase().includes(query.value.toLowerCase())
|
||||
)
|
||||
})
|
||||
@@ -4586,7 +4458,7 @@ describe('Mouse interactions', () => {
|
||||
// Verify we have combobox options
|
||||
let options = getComboboxOptions()
|
||||
expect(options).toHaveLength(3)
|
||||
options.forEach(option => assertComboboxOption(option))
|
||||
options.forEach((option) => assertComboboxOption(option))
|
||||
})
|
||||
)
|
||||
|
||||
@@ -5036,9 +4908,7 @@ describe('Mouse interactions', () => {
|
||||
<ComboboxButton>Trigger</ComboboxButton>
|
||||
<ComboboxOptions>
|
||||
<ComboboxOption value="alice">alice</ComboboxOption>
|
||||
<ComboboxOption disabled value="bob">
|
||||
bob
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="bob"> bob </ComboboxOption>
|
||||
<ComboboxOption value="charlie">charlie</ComboboxOption>
|
||||
</ComboboxOptions>
|
||||
</Combobox>
|
||||
@@ -5066,9 +4936,7 @@ describe('Mouse interactions', () => {
|
||||
<ComboboxButton>Trigger</ComboboxButton>
|
||||
<ComboboxOptions>
|
||||
<ComboboxOption value="alice">alice</ComboboxOption>
|
||||
<ComboboxOption disabled value="bob">
|
||||
bob
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="bob"> bob </ComboboxOption>
|
||||
<ComboboxOption value="charlie">charlie</ComboboxOption>
|
||||
</ComboboxOptions>
|
||||
</Combobox>
|
||||
@@ -5145,9 +5013,7 @@ describe('Mouse interactions', () => {
|
||||
<ComboboxButton>Trigger</ComboboxButton>
|
||||
<ComboboxOptions>
|
||||
<ComboboxOption value="alice">alice</ComboboxOption>
|
||||
<ComboboxOption disabled value="bob">
|
||||
bob
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="bob"> bob </ComboboxOption>
|
||||
<ComboboxOption value="charlie">charlie</ComboboxOption>
|
||||
</ComboboxOptions>
|
||||
</Combobox>
|
||||
@@ -5227,9 +5093,7 @@ describe('Mouse interactions', () => {
|
||||
<ComboboxButton>Trigger</ComboboxButton>
|
||||
<ComboboxOptions>
|
||||
<ComboboxOption value="alice">alice</ComboboxOption>
|
||||
<ComboboxOption disabled value="bob">
|
||||
bob
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="bob"> bob </ComboboxOption>
|
||||
<ComboboxOption value="charlie">charlie</ComboboxOption>
|
||||
</ComboboxOptions>
|
||||
</Combobox>
|
||||
@@ -5309,9 +5173,7 @@ describe('Mouse interactions', () => {
|
||||
<ComboboxButton>Trigger</ComboboxButton>
|
||||
<ComboboxOptions>
|
||||
<ComboboxOption value="alice">alice</ComboboxOption>
|
||||
<ComboboxOption disabled value="bob">
|
||||
bob
|
||||
</ComboboxOption>
|
||||
<ComboboxOption disabled value="bob"> bob </ComboboxOption>
|
||||
<ComboboxOption value="charlie">charlie</ComboboxOption>
|
||||
</ComboboxOptions>
|
||||
</Combobox>
|
||||
|
||||
@@ -131,8 +131,8 @@ export let Combobox = 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,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -152,7 +152,7 @@ export let Combobox = defineComponent({
|
||||
}
|
||||
},
|
||||
selectOption(id: string) {
|
||||
let option = options.value.find(item => item.id === id)
|
||||
let option = options.value.find((item) => item.id === id)
|
||||
if (!option) return
|
||||
|
||||
let { dataRef } = option
|
||||
@@ -193,7 +193,7 @@ export let Combobox = 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 = (() => {
|
||||
@@ -207,7 +207,7 @@ export let Combobox = defineComponent({
|
||||
},
|
||||
}
|
||||
|
||||
useWindowEvent('mousedown', event => {
|
||||
useWindowEvent('mousedown', (event) => {
|
||||
let target = event.target as HTMLElement
|
||||
let active = document.activeElement
|
||||
|
||||
|
||||
@@ -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,47 @@ beforeAll(() => {
|
||||
|
||||
afterAll(() => jest.restoreAllMocks())
|
||||
|
||||
function renderTemplate(input: string | Partial<Parameters<typeof defineComponent>[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<typeof defineComponent>[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 },
|
||||
render() {
|
||||
return h('div', [h('div', { 'aria-describedby': this.describedby }, ['No description'])])
|
||||
},
|
||||
setup() {
|
||||
let describedby = useDescriptions()
|
||||
return { describedby }
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
expect(format(container.firstElementChild)).toEqual(
|
||||
format(html`
|
||||
<div>
|
||||
<div>
|
||||
No description
|
||||
</div>
|
||||
<div>No description</div>
|
||||
</div>
|
||||
`)
|
||||
)
|
||||
})
|
||||
|
||||
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 },
|
||||
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 }
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
await new Promise<void>(nextTick)
|
||||
|
||||
@@ -82,12 +71,8 @@ it('should be possible to use useDescriptions and a single Description, and have
|
||||
format(html`
|
||||
<div>
|
||||
<div aria-describedby="headlessui-description-1">
|
||||
<p id="headlessui-description-1">
|
||||
I am a description
|
||||
</p>
|
||||
<span>
|
||||
Contents
|
||||
</span>
|
||||
<p id="headlessui-description-1">I am a description</p>
|
||||
<span>Contents</span>
|
||||
</div>
|
||||
</div>
|
||||
`)
|
||||
@@ -95,21 +80,24 @@ 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 },
|
||||
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 }
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
await new Promise<void>(nextTick)
|
||||
|
||||
@@ -117,15 +105,9 @@ it('should be possible to use useDescriptions and multiple Description component
|
||||
format(html`
|
||||
<div>
|
||||
<div aria-describedby="headlessui-description-1 headlessui-description-2">
|
||||
<p id="headlessui-description-1">
|
||||
I am a description
|
||||
</p>
|
||||
<span>
|
||||
Contents
|
||||
</span>
|
||||
<p id="headlessui-description-2">
|
||||
I am also a description
|
||||
</p>
|
||||
<p id="headlessui-description-1">I am a description</p>
|
||||
<span>Contents</span>
|
||||
<p id="headlessui-description-2">I am also a description</p>
|
||||
</div>
|
||||
</div>
|
||||
`)
|
||||
@@ -133,21 +115,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 },
|
||||
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 }
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
await new Promise<void>(nextTick)
|
||||
|
||||
@@ -155,9 +140,7 @@ it('should be possible to update a prop from the parent and it should reflect in
|
||||
format(html`
|
||||
<div>
|
||||
<div aria-describedby="headlessui-description-1">
|
||||
<p data-count="0" id="headlessui-description-1">
|
||||
I am a description
|
||||
</p>
|
||||
<p data-count="0" id="headlessui-description-1">I am a description</p>
|
||||
<button>+1</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -170,9 +153,7 @@ it('should be possible to update a prop from the parent and it should reflect in
|
||||
format(html`
|
||||
<div>
|
||||
<div aria-describedby="headlessui-description-1">
|
||||
<p data-count="1" id="headlessui-description-1">
|
||||
I am a description
|
||||
</p>
|
||||
<p data-count="1" id="headlessui-description-1">I am a description</p>
|
||||
<button>+1</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defineComponent, ref, nextTick, h } from 'vue'
|
||||
import { defineComponent, ref, nextTick, h, ComponentOptionsWithoutProps } from 'vue'
|
||||
import { render } from '../../test-utils/vue-testing-library'
|
||||
|
||||
import { Dialog, DialogOverlay, DialogTitle, DialogDescription } from './dialog'
|
||||
@@ -30,9 +30,7 @@ afterAll(() => jest.restoreAllMocks())
|
||||
|
||||
let TabSentinel = defineComponent({
|
||||
name: 'TabSentinel',
|
||||
template: html`
|
||||
<div :tabindex="0"></div>
|
||||
`,
|
||||
template: html` <div :tabindex="0"></div> `,
|
||||
})
|
||||
|
||||
jest.mock('../../hooks/use-id')
|
||||
@@ -44,7 +42,7 @@ beforeAll(() => {
|
||||
|
||||
afterAll(() => jest.restoreAllMocks())
|
||||
|
||||
function renderTemplate(input: string | Partial<Parameters<typeof defineComponent>[0]>) {
|
||||
function renderTemplate(input: string | ComponentOptionsWithoutProps) {
|
||||
let defaultComponents = { Dialog, DialogOverlay, DialogTitle, DialogDescription, TabSentinel }
|
||||
|
||||
if (typeof input === 'string') {
|
||||
|
||||
@@ -193,7 +193,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 +205,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 +215,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 +233,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 &&
|
||||
|
||||
@@ -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<Parameters<typeof defineComponent>[0]>) {
|
||||
function renderTemplate(input: string | ComponentOptionsWithoutProps) {
|
||||
let defaultComponents = { Disclosure, DisclosureButton, DisclosurePanel }
|
||||
|
||||
if (typeof input === 'string') {
|
||||
@@ -297,9 +297,7 @@ describe('Rendering', () => {
|
||||
renderTemplate(
|
||||
html`
|
||||
<Disclosure>
|
||||
<DisclosureButton>
|
||||
Trigger
|
||||
</DisclosureButton>
|
||||
<DisclosureButton> Trigger </DisclosureButton>
|
||||
</Disclosure>
|
||||
`
|
||||
)
|
||||
@@ -311,9 +309,7 @@ describe('Rendering', () => {
|
||||
renderTemplate(
|
||||
html`
|
||||
<Disclosure>
|
||||
<DisclosureButton type="submit">
|
||||
Trigger
|
||||
</DisclosureButton>
|
||||
<DisclosureButton type="submit"> Trigger </DisclosureButton>
|
||||
</Disclosure>
|
||||
`
|
||||
)
|
||||
@@ -327,14 +323,12 @@ describe('Rendering', () => {
|
||||
renderTemplate({
|
||||
template: html`
|
||||
<Disclosure>
|
||||
<DisclosureButton :as="CustomButton">
|
||||
Trigger
|
||||
</DisclosureButton>
|
||||
<DisclosureButton :as="CustomButton"> Trigger </DisclosureButton>
|
||||
</Disclosure>
|
||||
`,
|
||||
setup: () => ({
|
||||
CustomButton: defineComponent({
|
||||
setup: props => () => h('button', { ...props }),
|
||||
setup: (props) => () => h('button', { ...props }),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
@@ -349,9 +343,7 @@ describe('Rendering', () => {
|
||||
renderTemplate(
|
||||
html`
|
||||
<Disclosure>
|
||||
<DisclosureButton as="div">
|
||||
Trigger
|
||||
</DisclosureButton>
|
||||
<DisclosureButton as="div"> Trigger </DisclosureButton>
|
||||
</Disclosure>
|
||||
`
|
||||
)
|
||||
@@ -365,14 +357,12 @@ describe('Rendering', () => {
|
||||
renderTemplate({
|
||||
template: html`
|
||||
<Disclosure>
|
||||
<DisclosureButton :as="CustomButton">
|
||||
Trigger
|
||||
</DisclosureButton>
|
||||
<DisclosureButton :as="CustomButton"> Trigger </DisclosureButton>
|
||||
</Disclosure>
|
||||
`,
|
||||
setup: () => ({
|
||||
CustomButton: defineComponent({
|
||||
setup: props => () => h('div', props),
|
||||
setup: (props) => () => h('div', props),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -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<Parameters<typeof defineComponent>[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<void>(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<void>(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<void>(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<void>(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<void>(nextTick)
|
||||
|
||||
expect(spy.mock.calls[0][0]).toBe('There are no focusable elements inside the <FocusTrap />')
|
||||
})
|
||||
@@ -143,7 +143,7 @@ it(
|
||||
`,
|
||||
})
|
||||
|
||||
await new Promise(nextTick)
|
||||
await new Promise<void>(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`
|
||||
<div>
|
||||
<input id="item-1" ref="autoFocusRef" />
|
||||
<button id="item-2" @click="visible = true">
|
||||
Open modal
|
||||
</button>
|
||||
<button id="item-2" @click="visible = true">Open modal</button>
|
||||
|
||||
<FocusTrap v-if="visible">
|
||||
<button id="item-3" @click="visible = false">
|
||||
Close
|
||||
</button>
|
||||
<button id="item-3" @click="visible = false">Close</button>
|
||||
</FocusTrap>
|
||||
</div>
|
||||
`,
|
||||
@@ -214,7 +210,7 @@ it('should restore the previously focused element, before entering the FocusTrap
|
||||
},
|
||||
})
|
||||
|
||||
await new Promise(nextTick)
|
||||
await new Promise<void>(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<void>(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 () =
|
||||
<div>
|
||||
<button id="before">Before</button>
|
||||
<FocusTrap>
|
||||
<button id="item-a" style="display:none">
|
||||
Item A
|
||||
</button>
|
||||
<button id="item-b" style="display:none">
|
||||
Item B
|
||||
</button>
|
||||
<button id="item-a" style="display:none">Item A</button>
|
||||
<button id="item-b" style="display:none">Item B</button>
|
||||
<button id="item-c">Item C</button>
|
||||
<button id="item-d">Item D</button>
|
||||
</FocusTrap>
|
||||
@@ -328,9 +320,7 @@ it('should be possible skip "hidden" elements within the focus trap', async () =
|
||||
<FocusTrap>
|
||||
<button id="item-a">Item A</button>
|
||||
<button id="item-b">Item B</button>
|
||||
<button id="item-c" style="display:none">
|
||||
Item C
|
||||
</button>
|
||||
<button id="item-c" style="display:none">Item C</button>
|
||||
<button id="item-d">Item D</button>
|
||||
</FocusTrap>
|
||||
<button>After</button>
|
||||
@@ -364,9 +354,7 @@ it('should be possible skip disabled elements within the focus trap', async () =
|
||||
<FocusTrap>
|
||||
<button id="item-a">Item A</button>
|
||||
<button id="item-b">Item B</button>
|
||||
<button id="item-c" disabled>
|
||||
Item C
|
||||
</button>
|
||||
<button id="item-c" disabled>Item C</button>
|
||||
<button id="item-d">Item D</button>
|
||||
</FocusTrap>
|
||||
<button>After</button>
|
||||
|
||||
@@ -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,47 @@ beforeAll(() => {
|
||||
|
||||
afterAll(() => jest.restoreAllMocks())
|
||||
|
||||
function renderTemplate(input: string | Partial<Parameters<typeof defineComponent>[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<typeof defineComponent>[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 },
|
||||
render() {
|
||||
return h('div', [h('div', { 'aria-labelledby': this.labelledby }, ['No label'])])
|
||||
},
|
||||
setup() {
|
||||
let labelledby = useLabels()
|
||||
return { labelledby }
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
expect(format(container.firstElementChild)).toEqual(
|
||||
format(html`
|
||||
<div>
|
||||
<div>
|
||||
No label
|
||||
</div>
|
||||
<div>No label</div>
|
||||
</div>
|
||||
`)
|
||||
)
|
||||
})
|
||||
|
||||
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 },
|
||||
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 }
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
await new Promise<void>(nextTick)
|
||||
|
||||
@@ -82,12 +71,8 @@ it('should be possible to use useLabels and a single Label, and have them linked
|
||||
format(html`
|
||||
<div>
|
||||
<div aria-labelledby="headlessui-label-1">
|
||||
<label id="headlessui-label-1">
|
||||
I am a label
|
||||
</label>
|
||||
<span>
|
||||
Contents
|
||||
</span>
|
||||
<label id="headlessui-label-1">I am a label</label>
|
||||
<span>Contents</span>
|
||||
</div>
|
||||
</div>
|
||||
`)
|
||||
@@ -95,21 +80,24 @@ 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 },
|
||||
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 }
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
await new Promise<void>(nextTick)
|
||||
|
||||
@@ -117,15 +105,9 @@ it('should be possible to use useLabels and multiple Label components, and have
|
||||
format(html`
|
||||
<div>
|
||||
<div aria-labelledby="headlessui-label-1 headlessui-label-2">
|
||||
<label id="headlessui-label-1">
|
||||
I am a label
|
||||
</label>
|
||||
<span>
|
||||
Contents
|
||||
</span>
|
||||
<label id="headlessui-label-2">
|
||||
I am also a label
|
||||
</label>
|
||||
<label id="headlessui-label-1">I am a label</label>
|
||||
<span>Contents</span>
|
||||
<label id="headlessui-label-2">I am also a label</label>
|
||||
</div>
|
||||
</div>
|
||||
`)
|
||||
@@ -133,21 +115,24 @@ 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 },
|
||||
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 }
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
await new Promise<void>(nextTick)
|
||||
|
||||
@@ -155,9 +140,7 @@ it('should be possible to update a prop from the parent and it should reflect in
|
||||
format(html`
|
||||
<div>
|
||||
<div aria-labelledby="headlessui-label-1">
|
||||
<label data-count="0" id="headlessui-label-1">
|
||||
I am a label
|
||||
</label>
|
||||
<label data-count="0" id="headlessui-label-1">I am a label</label>
|
||||
<button>+1</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -170,9 +153,7 @@ it('should be possible to update a prop from the parent and it should reflect in
|
||||
format(html`
|
||||
<div>
|
||||
<div aria-labelledby="headlessui-label-1">
|
||||
<label data-count="1" id="headlessui-label-1">
|
||||
I am a label
|
||||
</label>
|
||||
<label data-count="1" id="headlessui-label-1">I am a label</label>
|
||||
<button>+1</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -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<void>((resolve) => {
|
||||
requestAnimationFrame(() => {
|
||||
requestAnimationFrame(() => {
|
||||
resolve()
|
||||
@@ -57,7 +65,7 @@ function nextFrame() {
|
||||
})
|
||||
}
|
||||
|
||||
function renderTemplate(input: string | Partial<Parameters<typeof defineComponent>[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`
|
||||
<Listbox v-model="value">
|
||||
<ListboxButton type="submit">
|
||||
Trigger
|
||||
</ListboxButton>
|
||||
<ListboxButton type="submit"> Trigger </ListboxButton>
|
||||
</Listbox>
|
||||
`,
|
||||
setup: () => ({ value: ref(null) }),
|
||||
@@ -405,15 +411,13 @@ describe('Rendering', () => {
|
||||
renderTemplate({
|
||||
template: html`
|
||||
<Listbox v-model="value">
|
||||
<ListboxButton :as="CustomButton">
|
||||
Trigger
|
||||
</ListboxButton>
|
||||
<ListboxButton :as="CustomButton"> Trigger </ListboxButton>
|
||||
</Listbox>
|
||||
`,
|
||||
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`
|
||||
<Listbox v-model="value">
|
||||
<ListboxButton as="div">
|
||||
Trigger
|
||||
</ListboxButton>
|
||||
<ListboxButton as="div"> Trigger </ListboxButton>
|
||||
</Listbox>
|
||||
`,
|
||||
setup: () => ({ value: ref(null) }),
|
||||
@@ -445,15 +447,13 @@ describe('Rendering', () => {
|
||||
renderTemplate({
|
||||
template: html`
|
||||
<Listbox v-model="value">
|
||||
<ListboxButton :as="CustomButton">
|
||||
Trigger
|
||||
</ListboxButton>
|
||||
<ListboxButton :as="CustomButton"> Trigger </ListboxButton>
|
||||
</Listbox>
|
||||
`,
|
||||
setup: () => ({
|
||||
value: ref(null),
|
||||
CustomButton: defineComponent({
|
||||
setup: props => () => h('div', props),
|
||||
setup: (props) => () => h('div', props),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
@@ -647,15 +647,9 @@ describe('Rendering composition', () => {
|
||||
<Listbox v-model="value">
|
||||
<ListboxButton>Trigger</ListboxButton>
|
||||
<ListboxOptions>
|
||||
<ListboxOption as="button" value="a">
|
||||
Option A
|
||||
</ListboxOption>
|
||||
<ListboxOption as="button" value="b">
|
||||
Option B
|
||||
</ListboxOption>
|
||||
<ListboxOption as="button" value="c">
|
||||
Option C
|
||||
</ListboxOption>
|
||||
<ListboxOption as="button" value="a"> Option A </ListboxOption>
|
||||
<ListboxOption as="button" value="b"> Option B </ListboxOption>
|
||||
<ListboxOption as="button" value="c"> Option C </ListboxOption>
|
||||
</ListboxOptions>
|
||||
</Listbox>
|
||||
`,
|
||||
@@ -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', () => {
|
||||
<Listbox>
|
||||
<ListboxButton>Trigger</ListboxButton>
|
||||
<OpenClosedWrite :open="true">
|
||||
<ListboxOptions v-slot="data">
|
||||
{{JSON.stringify(data)}}
|
||||
</ListboxOptions>
|
||||
<ListboxOptions v-slot="data"> {{JSON.stringify(data)}} </ListboxOptions>
|
||||
</OpenClosedWrite>
|
||||
</Listbox>
|
||||
`,
|
||||
@@ -734,9 +726,7 @@ describe('Composition', () => {
|
||||
<Listbox>
|
||||
<ListboxButton>Trigger</ListboxButton>
|
||||
<OpenClosedWrite :open="false">
|
||||
<ListboxOptions v-slot="data">
|
||||
{{JSON.stringify(data)}}
|
||||
</ListboxOptions>
|
||||
<ListboxOptions v-slot="data"> {{JSON.stringify(data)}} </ListboxOptions>
|
||||
</OpenClosedWrite>
|
||||
</Listbox>
|
||||
`,
|
||||
@@ -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', () => {
|
||||
<Listbox v-model="value">
|
||||
<ListboxButton>Trigger</ListboxButton>
|
||||
<ListboxOptions>
|
||||
<ListboxOption disabled value="a">
|
||||
Option A
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="a"> Option A </ListboxOption>
|
||||
<ListboxOption value="b">Option B</ListboxOption>
|
||||
<ListboxOption value="c">Option C</ListboxOption>
|
||||
</ListboxOptions>
|
||||
@@ -1130,12 +1118,8 @@ describe('Keyboard interactions', () => {
|
||||
<Listbox v-model="value">
|
||||
<ListboxButton>Trigger</ListboxButton>
|
||||
<ListboxOptions>
|
||||
<ListboxOption disabled value="a">
|
||||
Option A
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="b">
|
||||
Option B
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="a"> Option A </ListboxOption>
|
||||
<ListboxOption disabled value="b"> Option B </ListboxOption>
|
||||
<ListboxOption value="c">Option C</ListboxOption>
|
||||
</ListboxOptions>
|
||||
</Listbox>
|
||||
@@ -1170,15 +1154,9 @@ describe('Keyboard interactions', () => {
|
||||
<Listbox v-model="value">
|
||||
<ListboxButton>Trigger</ListboxButton>
|
||||
<ListboxOptions>
|
||||
<ListboxOption disabled value="a">
|
||||
Option A
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="b">
|
||||
Option B
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="c">
|
||||
Option C
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="a"> Option A </ListboxOption>
|
||||
<ListboxOption disabled value="b"> Option B </ListboxOption>
|
||||
<ListboxOption disabled value="c"> Option C </ListboxOption>
|
||||
</ListboxOptions>
|
||||
</Listbox>
|
||||
`,
|
||||
@@ -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', () => {
|
||||
<Listbox v-model="value">
|
||||
<ListboxButton>Trigger</ListboxButton>
|
||||
<ListboxOptions>
|
||||
<ListboxOption disabled value="a">
|
||||
Option A
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="a"> Option A </ListboxOption>
|
||||
<ListboxOption value="b">Option B</ListboxOption>
|
||||
<ListboxOption value="c">Option C</ListboxOption>
|
||||
</ListboxOptions>
|
||||
@@ -1509,12 +1485,8 @@ describe('Keyboard interactions', () => {
|
||||
<Listbox v-model="value">
|
||||
<ListboxButton>Trigger</ListboxButton>
|
||||
<ListboxOptions>
|
||||
<ListboxOption disabled value="a">
|
||||
Option A
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="b">
|
||||
Option B
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="a"> Option A </ListboxOption>
|
||||
<ListboxOption disabled value="b"> Option B </ListboxOption>
|
||||
<ListboxOption value="c">Option C</ListboxOption>
|
||||
</ListboxOptions>
|
||||
</Listbox>
|
||||
@@ -1549,15 +1521,9 @@ describe('Keyboard interactions', () => {
|
||||
<Listbox v-model="value">
|
||||
<ListboxButton>Trigger</ListboxButton>
|
||||
<ListboxOptions>
|
||||
<ListboxOption disabled value="a">
|
||||
Option A
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="b">
|
||||
Option B
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="c">
|
||||
Option C
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="a"> Option A </ListboxOption>
|
||||
<ListboxOption disabled value="b"> Option B </ListboxOption>
|
||||
<ListboxOption disabled value="c"> Option C </ListboxOption>
|
||||
</ListboxOptions>
|
||||
</Listbox>
|
||||
`,
|
||||
@@ -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', () => {
|
||||
<Listbox v-model="value">
|
||||
<ListboxButton>Trigger</ListboxButton>
|
||||
<ListboxOptions>
|
||||
<ListboxOption disabled value="a">
|
||||
Option A
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="a"> Option A </ListboxOption>
|
||||
<ListboxOption value="b">Option B</ListboxOption>
|
||||
<ListboxOption value="c">Option C</ListboxOption>
|
||||
</ListboxOptions>
|
||||
@@ -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', () => {
|
||||
<Listbox v-model="value">
|
||||
<ListboxButton>Trigger</ListboxButton>
|
||||
<ListboxOptions>
|
||||
<ListboxOption disabled value="a">
|
||||
Option A
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="b">
|
||||
Option B
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="a"> Option A </ListboxOption>
|
||||
<ListboxOption disabled value="b"> Option B </ListboxOption>
|
||||
<ListboxOption value="c">Option C</ListboxOption>
|
||||
</ListboxOptions>
|
||||
</Listbox>
|
||||
@@ -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', () => {
|
||||
<ListboxButton>Trigger</ListboxButton>
|
||||
<ListboxOptions>
|
||||
<ListboxOption value="a">Option A</ListboxOption>
|
||||
<ListboxOption disabled value="b">
|
||||
Option B
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="c">
|
||||
Option C
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="b"> Option B </ListboxOption>
|
||||
<ListboxOption disabled value="c"> Option C </ListboxOption>
|
||||
</ListboxOptions>
|
||||
</Listbox>
|
||||
`,
|
||||
@@ -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', () => {
|
||||
<Listbox v-model="value">
|
||||
<ListboxButton>Trigger</ListboxButton>
|
||||
<ListboxOptions>
|
||||
<ListboxOption disabled value="a">
|
||||
Option A
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="b">
|
||||
Option B
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="a"> Option A </ListboxOption>
|
||||
<ListboxOption disabled value="b"> Option B </ListboxOption>
|
||||
<ListboxOption value="c">Option C</ListboxOption>
|
||||
</ListboxOptions>
|
||||
</Listbox>
|
||||
@@ -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', () => {
|
||||
<ListboxOptions>
|
||||
<ListboxOption value="a">Option A</ListboxOption>
|
||||
<ListboxOption value="b">Option B</ListboxOption>
|
||||
<ListboxOption disabled value="c">
|
||||
Option C
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="d">
|
||||
Option D
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="c"> Option C </ListboxOption>
|
||||
<ListboxOption disabled value="d"> Option D </ListboxOption>
|
||||
</ListboxOptions>
|
||||
</Listbox>
|
||||
`,
|
||||
@@ -2599,15 +2547,9 @@ describe('Keyboard interactions', () => {
|
||||
<ListboxButton>Trigger</ListboxButton>
|
||||
<ListboxOptions>
|
||||
<ListboxOption value="a">Option A</ListboxOption>
|
||||
<ListboxOption disabled value="b">
|
||||
Option B
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="c">
|
||||
Option C
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="d">
|
||||
Option D
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="b"> Option B </ListboxOption>
|
||||
<ListboxOption disabled value="c"> Option C </ListboxOption>
|
||||
<ListboxOption disabled value="d"> Option D </ListboxOption>
|
||||
</ListboxOptions>
|
||||
</Listbox>
|
||||
`,
|
||||
@@ -2636,18 +2578,10 @@ describe('Keyboard interactions', () => {
|
||||
<Listbox v-model="value">
|
||||
<ListboxButton>Trigger</ListboxButton>
|
||||
<ListboxOptions>
|
||||
<ListboxOption disabled value="a">
|
||||
Option A
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="b">
|
||||
Option B
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="c">
|
||||
Option C
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="d">
|
||||
Option D
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="a"> Option A </ListboxOption>
|
||||
<ListboxOption disabled value="b"> Option B </ListboxOption>
|
||||
<ListboxOption disabled value="c"> Option C </ListboxOption>
|
||||
<ListboxOption disabled value="d"> Option D </ListboxOption>
|
||||
</ListboxOptions>
|
||||
</Listbox>
|
||||
`,
|
||||
@@ -2713,12 +2647,8 @@ describe('Keyboard interactions', () => {
|
||||
<ListboxOptions>
|
||||
<ListboxOption value="a">Option A</ListboxOption>
|
||||
<ListboxOption value="b">Option B</ListboxOption>
|
||||
<ListboxOption disabled value="c">
|
||||
Option C
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="d">
|
||||
Option D
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="c"> Option C </ListboxOption>
|
||||
<ListboxOption disabled value="d"> Option D </ListboxOption>
|
||||
</ListboxOptions>
|
||||
</Listbox>
|
||||
`,
|
||||
@@ -2751,15 +2681,9 @@ describe('Keyboard interactions', () => {
|
||||
<ListboxButton>Trigger</ListboxButton>
|
||||
<ListboxOptions>
|
||||
<ListboxOption value="a">Option A</ListboxOption>
|
||||
<ListboxOption disabled value="b">
|
||||
Option B
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="c">
|
||||
Option C
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="d">
|
||||
Option D
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="b"> Option B </ListboxOption>
|
||||
<ListboxOption disabled value="c"> Option C </ListboxOption>
|
||||
<ListboxOption disabled value="d"> Option D </ListboxOption>
|
||||
</ListboxOptions>
|
||||
</Listbox>
|
||||
`,
|
||||
@@ -2788,18 +2712,10 @@ describe('Keyboard interactions', () => {
|
||||
<Listbox v-model="value">
|
||||
<ListboxButton>Trigger</ListboxButton>
|
||||
<ListboxOptions>
|
||||
<ListboxOption disabled value="a">
|
||||
Option A
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="b">
|
||||
Option B
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="c">
|
||||
Option C
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="d">
|
||||
Option D
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="a"> Option A </ListboxOption>
|
||||
<ListboxOption disabled value="b"> Option B </ListboxOption>
|
||||
<ListboxOption disabled value="c"> Option C </ListboxOption>
|
||||
<ListboxOption disabled value="d"> Option D </ListboxOption>
|
||||
</ListboxOptions>
|
||||
</Listbox>
|
||||
`,
|
||||
@@ -2863,12 +2779,8 @@ describe('Keyboard interactions', () => {
|
||||
<Listbox v-model="value">
|
||||
<ListboxButton>Trigger</ListboxButton>
|
||||
<ListboxOptions>
|
||||
<ListboxOption disabled value="a">
|
||||
Option A
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="b">
|
||||
Option B
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="a"> Option A </ListboxOption>
|
||||
<ListboxOption disabled value="b"> Option B </ListboxOption>
|
||||
<ListboxOption value="c">Option C</ListboxOption>
|
||||
<ListboxOption value="d">Option D</ListboxOption>
|
||||
</ListboxOptions>
|
||||
@@ -2901,15 +2813,9 @@ describe('Keyboard interactions', () => {
|
||||
<Listbox v-model="value">
|
||||
<ListboxButton>Trigger</ListboxButton>
|
||||
<ListboxOptions>
|
||||
<ListboxOption disabled value="a">
|
||||
Option A
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="b">
|
||||
Option B
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="c">
|
||||
Option C
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="a"> Option A </ListboxOption>
|
||||
<ListboxOption disabled value="b"> Option B </ListboxOption>
|
||||
<ListboxOption disabled value="c"> Option C </ListboxOption>
|
||||
<ListboxOption value="d">Option D</ListboxOption>
|
||||
</ListboxOptions>
|
||||
</Listbox>
|
||||
@@ -2939,18 +2845,10 @@ describe('Keyboard interactions', () => {
|
||||
<Listbox v-model="value">
|
||||
<ListboxButton>Trigger</ListboxButton>
|
||||
<ListboxOptions>
|
||||
<ListboxOption disabled value="a">
|
||||
Option A
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="b">
|
||||
Option B
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="c">
|
||||
Option C
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="d">
|
||||
Option D
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="a"> Option A </ListboxOption>
|
||||
<ListboxOption disabled value="b"> Option B </ListboxOption>
|
||||
<ListboxOption disabled value="c"> Option C </ListboxOption>
|
||||
<ListboxOption disabled value="d"> Option D </ListboxOption>
|
||||
</ListboxOptions>
|
||||
</Listbox>
|
||||
`,
|
||||
@@ -3014,12 +2912,8 @@ describe('Keyboard interactions', () => {
|
||||
<Listbox v-model="value">
|
||||
<ListboxButton>Trigger</ListboxButton>
|
||||
<ListboxOptions>
|
||||
<ListboxOption disabled value="a">
|
||||
Option A
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="b">
|
||||
Option B
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="a"> Option A </ListboxOption>
|
||||
<ListboxOption disabled value="b"> Option B </ListboxOption>
|
||||
<ListboxOption value="c">Option C</ListboxOption>
|
||||
<ListboxOption value="d">Option D</ListboxOption>
|
||||
</ListboxOptions>
|
||||
@@ -3052,15 +2946,9 @@ describe('Keyboard interactions', () => {
|
||||
<Listbox v-model="value">
|
||||
<ListboxButton>Trigger</ListboxButton>
|
||||
<ListboxOptions>
|
||||
<ListboxOption disabled value="a">
|
||||
Option A
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="b">
|
||||
Option B
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="c">
|
||||
Option C
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="a"> Option A </ListboxOption>
|
||||
<ListboxOption disabled value="b"> Option B </ListboxOption>
|
||||
<ListboxOption disabled value="c"> Option C </ListboxOption>
|
||||
<ListboxOption value="d">Option D</ListboxOption>
|
||||
</ListboxOptions>
|
||||
</Listbox>
|
||||
@@ -3090,18 +2978,10 @@ describe('Keyboard interactions', () => {
|
||||
<Listbox v-model="value">
|
||||
<ListboxButton>Trigger</ListboxButton>
|
||||
<ListboxOptions>
|
||||
<ListboxOption disabled value="a">
|
||||
Option A
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="b">
|
||||
Option B
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="c">
|
||||
Option C
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="d">
|
||||
Option D
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="a"> Option A </ListboxOption>
|
||||
<ListboxOption disabled value="b"> Option B </ListboxOption>
|
||||
<ListboxOption disabled value="c"> Option C </ListboxOption>
|
||||
<ListboxOption disabled value="d"> Option D </ListboxOption>
|
||||
</ListboxOptions>
|
||||
</Listbox>
|
||||
`,
|
||||
@@ -3252,9 +3132,7 @@ describe('Keyboard interactions', () => {
|
||||
<ListboxButton>Trigger</ListboxButton>
|
||||
<ListboxOptions>
|
||||
<ListboxOption value="alice">alice</ListboxOption>
|
||||
<ListboxOption disabled value="bob">
|
||||
bob
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="bob"> bob </ListboxOption>
|
||||
<ListboxOption value="charlie">charlie</ListboxOption>
|
||||
</ListboxOptions>
|
||||
</Listbox>
|
||||
@@ -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', () => {
|
||||
<ListboxButton>Trigger</ListboxButton>
|
||||
<ListboxOptions>
|
||||
<ListboxOption value="alice">alice</ListboxOption>
|
||||
<ListboxOption disabled value="bob">
|
||||
bob
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="bob"> bob </ListboxOption>
|
||||
<ListboxOption value="charlie">charlie</ListboxOption>
|
||||
</ListboxOptions>
|
||||
</Listbox>
|
||||
@@ -3874,9 +3750,7 @@ describe('Mouse interactions', () => {
|
||||
<ListboxButton>Trigger</ListboxButton>
|
||||
<ListboxOptions>
|
||||
<ListboxOption value="alice">alice</ListboxOption>
|
||||
<ListboxOption disabled value="bob">
|
||||
bob
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="bob"> bob </ListboxOption>
|
||||
<ListboxOption value="charlie">charlie</ListboxOption>
|
||||
</ListboxOptions>
|
||||
</Listbox>
|
||||
@@ -3951,9 +3825,7 @@ describe('Mouse interactions', () => {
|
||||
<ListboxButton>Trigger</ListboxButton>
|
||||
<ListboxOptions>
|
||||
<ListboxOption value="alice">alice</ListboxOption>
|
||||
<ListboxOption disabled value="bob">
|
||||
bob
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="bob"> bob </ListboxOption>
|
||||
<ListboxOption value="charlie">charlie</ListboxOption>
|
||||
</ListboxOptions>
|
||||
</Listbox>
|
||||
@@ -4031,9 +3903,7 @@ describe('Mouse interactions', () => {
|
||||
<ListboxButton>Trigger</ListboxButton>
|
||||
<ListboxOptions>
|
||||
<ListboxOption value="alice">alice</ListboxOption>
|
||||
<ListboxOption disabled value="bob">
|
||||
bob
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="bob"> bob </ListboxOption>
|
||||
<ListboxOption value="charlie">charlie</ListboxOption>
|
||||
</ListboxOptions>
|
||||
</Listbox>
|
||||
@@ -4111,9 +3981,7 @@ describe('Mouse interactions', () => {
|
||||
<ListboxButton>Trigger</ListboxButton>
|
||||
<ListboxOptions>
|
||||
<ListboxOption value="alice">alice</ListboxOption>
|
||||
<ListboxOption disabled value="bob">
|
||||
bob
|
||||
</ListboxOption>
|
||||
<ListboxOption disabled value="bob"> bob </ListboxOption>
|
||||
<ListboxOption value="charlie">charlie</ListboxOption>
|
||||
</ListboxOptions>
|
||||
</Listbox>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -529,10 +529,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
|
||||
})
|
||||
|
||||
|
||||
@@ -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<void>((resolve) => {
|
||||
requestAnimationFrame(() => {
|
||||
requestAnimationFrame(() => {
|
||||
resolve()
|
||||
@@ -53,7 +61,7 @@ function nextFrame() {
|
||||
})
|
||||
}
|
||||
|
||||
function renderTemplate(input: string | Partial<Parameters<typeof defineComponent>[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(
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -452,10 +452,7 @@ export let MenuItem = defineComponent({
|
||||
|
||||
let dataRef = ref<MenuItemDataRef['value']>({ 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
|
||||
})
|
||||
|
||||
|
||||
@@ -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<Parameters<typeof defineComponent>[0]>) {
|
||||
function renderTemplate(input: string | ComponentOptionsWithoutProps) {
|
||||
let defaultComponents = {
|
||||
Popover,
|
||||
PopoverGroup,
|
||||
@@ -345,9 +345,7 @@ describe('Rendering', () => {
|
||||
renderTemplate(
|
||||
html`
|
||||
<Popover>
|
||||
<PopoverButton type="submit">
|
||||
Trigger
|
||||
</PopoverButton>
|
||||
<PopoverButton type="submit"> Trigger </PopoverButton>
|
||||
</Popover>
|
||||
`
|
||||
)
|
||||
@@ -361,14 +359,12 @@ describe('Rendering', () => {
|
||||
renderTemplate({
|
||||
template: html`
|
||||
<Popover>
|
||||
<PopoverButton :as="CustomButton">
|
||||
Trigger
|
||||
</PopoverButton>
|
||||
<PopoverButton :as="CustomButton"> Trigger </PopoverButton>
|
||||
</Popover>
|
||||
`,
|
||||
setup: () => ({
|
||||
CustomButton: defineComponent({
|
||||
setup: props => () => h('button', { ...props }),
|
||||
setup: (props) => () => h('button', { ...props }),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
@@ -383,9 +379,7 @@ describe('Rendering', () => {
|
||||
renderTemplate(
|
||||
html`
|
||||
<Popover>
|
||||
<PopoverButton as="div">
|
||||
Trigger
|
||||
</PopoverButton>
|
||||
<PopoverButton as="div"> Trigger </PopoverButton>
|
||||
</Popover>
|
||||
`
|
||||
)
|
||||
@@ -399,14 +393,12 @@ describe('Rendering', () => {
|
||||
renderTemplate({
|
||||
template: html`
|
||||
<Popover>
|
||||
<PopoverButton :as="CustomButton">
|
||||
Trigger
|
||||
</PopoverButton>
|
||||
<PopoverButton :as="CustomButton"> Trigger </PopoverButton>
|
||||
</Popover>
|
||||
`,
|
||||
setup: () => ({
|
||||
CustomButton: defineComponent({
|
||||
setup: props => () => h('div', props),
|
||||
setup: (props) => () => h('div', props),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
@@ -569,9 +561,7 @@ describe('Rendering', () => {
|
||||
<Popover>
|
||||
<PopoverButton>Trigger</PopoverButton>
|
||||
<PopoverPanel focus>
|
||||
<a href="/" style="display:none">
|
||||
Link 1
|
||||
</a>
|
||||
<a href="/" style="display:none"> Link 1 </a>
|
||||
<a href="/">Link 2</a>
|
||||
</PopoverPanel>
|
||||
</Popover>
|
||||
@@ -757,9 +747,7 @@ describe('Composition', () => {
|
||||
<Popover>
|
||||
<PopoverButton>Trigger</PopoverButton>
|
||||
<OpenClosedWrite :open="true">
|
||||
<PopoverPanel v-slot="data">
|
||||
{{JSON.stringify(data)}}
|
||||
</PopoverPanel>
|
||||
<PopoverPanel v-slot="data"> {{JSON.stringify(data)}} </PopoverPanel>
|
||||
</OpenClosedWrite>
|
||||
</Popover>
|
||||
`,
|
||||
@@ -787,9 +775,7 @@ describe('Composition', () => {
|
||||
<Popover>
|
||||
<PopoverButton>Trigger</PopoverButton>
|
||||
<OpenClosedWrite :open="false">
|
||||
<PopoverPanel v-slot="data">
|
||||
{{JSON.stringify(data)}}
|
||||
</PopoverPanel>
|
||||
<PopoverPanel v-slot="data"> {{JSON.stringify(data)}} </PopoverPanel>
|
||||
</OpenClosedWrite>
|
||||
</Popover>
|
||||
`,
|
||||
|
||||
@@ -528,7 +528,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
|
||||
@@ -624,7 +624,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)
|
||||
|
||||
@@ -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<Parameters<typeof defineComponent>[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`
|
||||
<main id="parent">
|
||||
<button id="a" @click="toggleA">
|
||||
Toggle A
|
||||
</button>
|
||||
<button id="b" @click="toggleB">
|
||||
Toggle B
|
||||
</button>
|
||||
<button id="a" @click="toggleA">Toggle A</button>
|
||||
<button id="b" @click="toggleB">Toggle B</button>
|
||||
|
||||
<Portal v-if="renderA">
|
||||
<p id="content1">Contents 1 ...</p>
|
||||
@@ -182,19 +178,11 @@ it('should be possible to render multiple portals at the same time', async () =>
|
||||
renderTemplate({
|
||||
template: html`
|
||||
<main id="parent">
|
||||
<button id="a" @click="toggleA">
|
||||
Toggle A
|
||||
</button>
|
||||
<button id="b" @click="toggleB">
|
||||
Toggle B
|
||||
</button>
|
||||
<button id="c" @click="toggleC">
|
||||
Toggle C
|
||||
</button>
|
||||
<button id="a" @click="toggleA">Toggle A</button>
|
||||
<button id="b" @click="toggleB">Toggle B</button>
|
||||
<button id="c" @click="toggleC">Toggle C</button>
|
||||
|
||||
<button id="double" @click="toggleAB">
|
||||
Toggle A & B
|
||||
</button>
|
||||
<button id="double" @click="toggleAB">Toggle A & B</button>
|
||||
|
||||
<Portal v-if="renderA">
|
||||
<p id="content1">Contents 1 ...</p>
|
||||
@@ -269,12 +257,8 @@ it('should be possible to tamper with the modal root and restore correctly', asy
|
||||
renderTemplate({
|
||||
template: html`
|
||||
<main id="parent">
|
||||
<button id="a" @click="toggleA">
|
||||
Toggle A
|
||||
</button>
|
||||
<button id="b" @click="toggleB">
|
||||
Toggle B
|
||||
</button>
|
||||
<button id="a" @click="toggleA">Toggle A</button>
|
||||
<button id="b" @click="toggleB">Toggle B</button>
|
||||
|
||||
<Portal v-if="renderA">
|
||||
<p id="content1">Contents 1 ...</p>
|
||||
@@ -325,9 +309,7 @@ it('should be possible to force the Portal into a specific element using PortalG
|
||||
renderTemplate({
|
||||
template: html`
|
||||
<main>
|
||||
<aside ref="container" id="group-1">
|
||||
A
|
||||
</aside>
|
||||
<aside ref="container" id="group-1">A</aside>
|
||||
|
||||
<PortalGroup :target="container">
|
||||
<section id="group-2">
|
||||
@@ -346,6 +328,6 @@ it('should be possible to force the Portal into a specific element using PortalG
|
||||
await new Promise<void>(nextTick)
|
||||
|
||||
expect(document.body.innerHTML).toMatchInlineSnapshot(
|
||||
`"<div><div><div data-v-app=\\"\\"><main><aside id=\\"group-1\\"> A <div>Next to A</div></aside><section id=\\"group-2\\"><span>B</span></section><!--teleport start--><!--teleport end--></main></div></div></div>"`
|
||||
`"<div><div><div data-v-app=\\"\\"><main><aside id=\\"group-1\\">A<div>Next to A</div></aside><section id=\\"group-2\\"><span>B</span></section><!--teleport start--><!--teleport end--></main></div></div></div>"`
|
||||
)
|
||||
})
|
||||
|
||||
@@ -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<void>((resolve) => {
|
||||
requestAnimationFrame(() => {
|
||||
requestAnimationFrame(() => {
|
||||
resolve()
|
||||
@@ -34,7 +34,7 @@ function nextFrame() {
|
||||
})
|
||||
}
|
||||
|
||||
function renderTemplate(input: string | Partial<Parameters<typeof defineComponent>[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`
|
||||
<RadioGroup v-model="deliveryMethod" />
|
||||
`,
|
||||
template: html` <RadioGroup v-model="deliveryMethod" /> `,
|
||||
setup() {
|
||||
let deliveryMethod = ref(undefined)
|
||||
return { deliveryMethod }
|
||||
|
||||
@@ -99,19 +99,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 +129,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 +155,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 +169,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 +186,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 +199,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)
|
||||
}
|
||||
|
||||
@@ -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<Parameters<typeof defineComponent>[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<Parameters<typeof defineComponen
|
||||
describe('Safe guards', () => {
|
||||
it('should be possible to render a Switch without crashing', () => {
|
||||
renderTemplate({
|
||||
template: html`
|
||||
<Switch v-model="checked" />
|
||||
`,
|
||||
template: html` <Switch v-model="checked" /> `,
|
||||
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`
|
||||
<Switch as="span" v-model="checked" />
|
||||
`,
|
||||
template: html` <Switch as="span" v-model="checked" /> `,
|
||||
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`
|
||||
<Switch as="span" v-model="checked" />
|
||||
`,
|
||||
template: html` <Switch as="span" v-model="checked" /> `,
|
||||
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`
|
||||
<Switch v-model="checked">
|
||||
Trigger
|
||||
</Switch>
|
||||
`,
|
||||
template: html` <Switch v-model="checked"> Trigger </Switch> `,
|
||||
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`
|
||||
<Switch v-model="checked" type="submit">
|
||||
Trigger
|
||||
</Switch>
|
||||
`,
|
||||
template: html` <Switch v-model="checked" type="submit"> Trigger </Switch> `,
|
||||
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`
|
||||
<Switch v-model="checked" :as="CustomButton">
|
||||
Trigger
|
||||
</Switch>
|
||||
`,
|
||||
template: html` <Switch v-model="checked" :as="CustomButton"> Trigger </Switch> `,
|
||||
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`
|
||||
<Switch v-model="checked" as="div">
|
||||
Trigger
|
||||
</Switch>
|
||||
`,
|
||||
template: html` <Switch v-model="checked" as="div"> Trigger </Switch> `,
|
||||
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`
|
||||
<Switch v-model="checked" :as="CustomButton">
|
||||
Trigger
|
||||
</Switch>
|
||||
`,
|
||||
template: html` <Switch v-model="checked" :as="CustomButton"> Trigger </Switch> `,
|
||||
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`
|
||||
<SwitchGroup>
|
||||
<SwitchLabel>Label B</SwitchLabel>
|
||||
<Switch v-model="checked">
|
||||
Label A
|
||||
</Switch>
|
||||
<Switch v-model="checked"> Label A </Switch>
|
||||
</SwitchGroup>
|
||||
`,
|
||||
setup: () => ({ checked: ref(false) }),
|
||||
@@ -234,9 +206,7 @@ describe('Render composition', () => {
|
||||
renderTemplate({
|
||||
template: html`
|
||||
<SwitchGroup>
|
||||
<Switch v-model="checked">
|
||||
Label A
|
||||
</Switch>
|
||||
<Switch v-model="checked"> Label A </Switch>
|
||||
<SwitchLabel>Label B</SwitchLabel>
|
||||
</SwitchGroup>
|
||||
`,
|
||||
@@ -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`
|
||||
<Switch v-model="checked" />
|
||||
`,
|
||||
template: html` <Switch v-model="checked" /> `,
|
||||
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`
|
||||
<Switch v-model="checked" />
|
||||
`,
|
||||
template: html` <Switch v-model="checked" /> `,
|
||||
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`
|
||||
<Switch v-model="checked" />
|
||||
`,
|
||||
template: html` <Switch v-model="checked" /> `,
|
||||
setup() {
|
||||
let checked = ref(false)
|
||||
watch([checked], () => handleChange(checked.value))
|
||||
|
||||
@@ -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<Parameters<typeof defineComponent>[0]>) {
|
||||
function renderTemplate(input: string | ComponentOptionsWithoutProps) {
|
||||
let defaultComponents = { TabGroup, TabList, Tab, TabPanels, TabPanel }
|
||||
|
||||
if (typeof input === 'string') {
|
||||
|
||||
@@ -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)
|
||||
@@ -220,7 +220,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()
|
||||
|
||||
@@ -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<Parameters<typeof defineComponent>[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`
|
||||
<TransitionRoot :show="true" class="transition" />
|
||||
`,
|
||||
template: html` <TransitionRoot :show="true" class="transition" /> `,
|
||||
})
|
||||
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`
|
||||
<TransitionRoot :show="true">Children</TransitionRoot>
|
||||
`,
|
||||
template: html`<TransitionRoot :show="true">Children</TransitionRoot>`,
|
||||
})
|
||||
|
||||
expect(container.firstChild).toMatchInlineSnapshot(html`
|
||||
expect(container.firstChild).toMatchInlineSnapshot(`
|
||||
<div>
|
||||
Children
|
||||
</div>
|
||||
@@ -106,9 +102,7 @@ describe('Setup API', () => {
|
||||
it('should passthrough all the props (that we do not use internally)', () => {
|
||||
let { container } = renderTemplate({
|
||||
template: html`
|
||||
<TransitionRoot :show="true" id="root" class="text-blue-400">
|
||||
Children
|
||||
</TransitionRoot>
|
||||
<TransitionRoot :show="true" id="root" class="text-blue-400"> Children </TransitionRoot>
|
||||
`,
|
||||
})
|
||||
|
||||
@@ -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`
|
||||
<TransitionRoot :show="true" as="a">
|
||||
Children
|
||||
</TransitionRoot>
|
||||
`,
|
||||
template: html` <TransitionRoot :show="true" as="a"> Children </TransitionRoot> `,
|
||||
})
|
||||
|
||||
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`
|
||||
<TransitionRoot :show="false">Children</TransitionRoot>
|
||||
`,
|
||||
template: html` <TransitionRoot :show="false">Children</TransitionRoot> `,
|
||||
})
|
||||
|
||||
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`
|
||||
<TransitionRoot :show="true" as="a">
|
||||
Children
|
||||
</TransitionRoot>
|
||||
`,
|
||||
template: html` <TransitionRoot :show="true" as="a"> Children </TransitionRoot> `,
|
||||
})
|
||||
|
||||
expect(container.firstChild).toMatchInlineSnapshot(`
|
||||
@@ -470,9 +454,7 @@ describe('Transitions', () => {
|
||||
<span>Hello!</span>
|
||||
</TransitionRoot>
|
||||
|
||||
<button data-testid="toggle" @click="show = !show">
|
||||
Toggle
|
||||
</button>
|
||||
<button data-testid="toggle" @click="show = !show">Toggle</button>
|
||||
`,
|
||||
setup() {
|
||||
let show = ref(false)
|
||||
@@ -525,9 +507,7 @@ describe('Transitions', () => {
|
||||
<span>Hello!</span>
|
||||
</TransitionRoot>
|
||||
|
||||
<button data-testid="toggle" @click="show = !show">
|
||||
Toggle
|
||||
</button>
|
||||
<button data-testid="toggle" @click="show = !show">Toggle</button>
|
||||
`,
|
||||
setup() {
|
||||
let show = ref(false)
|
||||
@@ -580,9 +560,7 @@ describe('Transitions', () => {
|
||||
<span>Hello!</span>
|
||||
</TransitionRoot>
|
||||
|
||||
<button data-testid="toggle" @click="show = !show">
|
||||
Toggle
|
||||
</button>
|
||||
<button data-testid="toggle" @click="show = !show">Toggle</button>
|
||||
`,
|
||||
setup() {
|
||||
let show = ref(false)
|
||||
@@ -630,9 +608,7 @@ describe('Transitions', () => {
|
||||
<span>Hello!</span>
|
||||
</TransitionRoot>
|
||||
|
||||
<button data-testid="toggle" @click="show = !show">
|
||||
Toggle
|
||||
</button>
|
||||
<button data-testid="toggle" @click="show = !show">Toggle</button>
|
||||
`,
|
||||
setup() {
|
||||
let show = ref(false)
|
||||
@@ -687,9 +663,7 @@ describe('Transitions', () => {
|
||||
<span>Hello!</span>
|
||||
</TransitionRoot>
|
||||
|
||||
<button data-testid="toggle" @click="show = !show">
|
||||
Toggle
|
||||
</button>
|
||||
<button data-testid="toggle" @click="show = !show">Toggle</button>
|
||||
`,
|
||||
setup() {
|
||||
let show = ref(true)
|
||||
@@ -753,9 +727,7 @@ describe('Transitions', () => {
|
||||
<span>Hello!</span>
|
||||
</TransitionRoot>
|
||||
|
||||
<button data-testid="toggle" @click="show = !show">
|
||||
Toggle
|
||||
</button>
|
||||
<button data-testid="toggle" @click="show = !show">Toggle</button>
|
||||
`,
|
||||
setup() {
|
||||
let show = ref(true)
|
||||
@@ -822,9 +794,7 @@ describe('Transitions', () => {
|
||||
<span>Hello!</span>
|
||||
</TransitionRoot>
|
||||
|
||||
<button data-testid="toggle" @click="show = !show">
|
||||
Toggle
|
||||
</button>
|
||||
<button data-testid="toggle" @click="show = !show">Toggle</button>
|
||||
`,
|
||||
setup() {
|
||||
let show = ref(false)
|
||||
@@ -918,9 +888,7 @@ describe('Transitions', () => {
|
||||
<span>Hello!</span>
|
||||
</TransitionRoot>
|
||||
|
||||
<button data-testid="toggle" @click="show = !show">
|
||||
Toggle
|
||||
</button>
|
||||
<button data-testid="toggle" @click="show = !show">Toggle</button>
|
||||
`,
|
||||
setup() {
|
||||
let show = ref(false)
|
||||
@@ -1021,9 +989,7 @@ describe('Transitions', () => {
|
||||
</TransitionChild>
|
||||
</TransitionRoot>
|
||||
|
||||
<button data-testid="toggle" @click="show = !show">
|
||||
Toggle
|
||||
</button>
|
||||
<button data-testid="toggle" @click="show = !show">Toggle</button>
|
||||
`,
|
||||
setup() {
|
||||
let show = ref(true)
|
||||
@@ -1113,9 +1079,7 @@ describe('Transitions', () => {
|
||||
</TransitionChild>
|
||||
</TransitionRoot>
|
||||
|
||||
<button data-testid="toggle" @click="show = !show">
|
||||
Toggle
|
||||
</button>
|
||||
<button data-testid="toggle" @click="show = !show">Toggle</button>
|
||||
`,
|
||||
setup() {
|
||||
let show = ref(true)
|
||||
@@ -1227,9 +1191,7 @@ describe('Events', () => {
|
||||
<span>Hello!</span>
|
||||
</TransitionRoot>
|
||||
|
||||
<button data-testid="toggle" @click="show = !show">
|
||||
Toggle
|
||||
</button>
|
||||
<button data-testid="toggle" @click="show = !show">Toggle</button>
|
||||
`,
|
||||
setup() {
|
||||
let show = ref(false)
|
||||
|
||||
@@ -31,7 +31,7 @@ import {
|
||||
type ID = ReturnType<typeof useId>
|
||||
|
||||
function splitClasses(classes: string = '') {
|
||||
return classes.split(' ').filter(className => className.trim().length > 1)
|
||||
return classes.split(' ').filter((className) => className.trim().length > 1)
|
||||
}
|
||||
|
||||
interface TransitionContextValues {
|
||||
@@ -292,7 +292,7 @@ export let TransitionChild = defineComponent({
|
||||
enterFromClasses,
|
||||
enterToClasses,
|
||||
enteredClasses,
|
||||
reason => {
|
||||
(reason) => {
|
||||
isTransitioning.value = false
|
||||
if (reason === Reason.Finished) emit('afterEnter')
|
||||
}
|
||||
@@ -303,7 +303,7 @@ export let TransitionChild = defineComponent({
|
||||
leaveFromClasses,
|
||||
leaveToClasses,
|
||||
enteredClasses,
|
||||
reason => {
|
||||
(reason) => {
|
||||
isTransitioning.value = false
|
||||
|
||||
if (reason !== Reason.Finished) return
|
||||
|
||||
@@ -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('<div></div>')
|
||||
@@ -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')
|
||||
})
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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<Parameters<typeof defineComponent>[0]>) {
|
||||
function renderTemplate(input: string | ComponentOptionsWithoutProps) {
|
||||
let defaultComponents = {}
|
||||
|
||||
if (typeof input === 'string') {
|
||||
@@ -35,16 +35,12 @@ function renderTemplate(input: string | Partial<Parameters<typeof defineComponen
|
||||
|
||||
let Before = defineComponent({
|
||||
name: 'Before',
|
||||
template: html`
|
||||
<div>before</div>
|
||||
`,
|
||||
template: html` <div>before</div> `,
|
||||
})
|
||||
|
||||
let After = defineComponent({
|
||||
name: 'After',
|
||||
template: html`
|
||||
<div>after</div>
|
||||
`,
|
||||
template: html` <div>after</div> `,
|
||||
})
|
||||
|
||||
it('should be possible to inert other elements', async () => {
|
||||
|
||||
@@ -32,7 +32,7 @@ export function useInertOthers<TElement extends HTMLElement>(
|
||||
container: Ref<TElement | null>,
|
||||
enabled: Ref<boolean> = ref(true)
|
||||
) {
|
||||
watchEffect(onInvalidate => {
|
||||
watchEffect((onInvalidate) => {
|
||||
if (!enabled.value) return
|
||||
if (!container.value) return
|
||||
|
||||
@@ -50,7 +50,7 @@ export function useInertOthers<TElement extends HTMLElement>(
|
||||
}
|
||||
|
||||
// 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<TElement extends HTMLElement>(
|
||||
// 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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -7,7 +7,7 @@ export function useWindowEvent<TType extends keyof WindowEventMap>(
|
||||
) {
|
||||
if (typeof window === 'undefined') return
|
||||
|
||||
watchEffect(onInvalidate => {
|
||||
watchEffect((onInvalidate) => {
|
||||
window.addEventListener(type, listener, options)
|
||||
|
||||
onInvalidate(() => {
|
||||
|
||||
@@ -24,7 +24,7 @@ export function useStackContext() {
|
||||
export function useElemenStack(element: Ref<HTMLElement | null> | null) {
|
||||
let notify = useStackContext()
|
||||
|
||||
watchEffect(onInvalidate => {
|
||||
watchEffect((onInvalidate) => {
|
||||
let domElement = element?.value
|
||||
if (!domElement) return
|
||||
|
||||
|
||||
@@ -1256,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
|
||||
}
|
||||
|
||||
@@ -1612,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')
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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<Parameters<typeof defineComponent>[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<Record<string, string | ((event: any) => 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)
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ export function shift(event: Partial<KeyboardEvent>) {
|
||||
}
|
||||
|
||||
export function word(input: string): Partial<KeyboardEvent>[] {
|
||||
let result = input.split('').map(key => ({ key }))
|
||||
let result = input.split('').map((key) => ({ key }))
|
||||
|
||||
d.enqueue(() => {
|
||||
let element = document.activeElement
|
||||
@@ -152,7 +152,7 @@ export async function type(events: Partial<KeyboardEvent>[], 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,
|
||||
@@ -344,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(',')
|
||||
|
||||
|
||||
@@ -5,10 +5,10 @@ type FunctionPropertyNames<T> = {
|
||||
|
||||
export function suppressConsoleLogs<T extends unknown[]>(
|
||||
cb: (...args: T) => void,
|
||||
type: FunctionPropertyNames<typeof global.console> = 'warn'
|
||||
type: FunctionPropertyNames<typeof globalThis.console> = '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<void>((resolve, reject) => {
|
||||
Promise.resolve(cb(...args)).then(resolve, reject)
|
||||
|
||||
@@ -40,7 +40,7 @@ export function calculateActiveIndex<TItem>(
|
||||
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<TItem>(
|
||||
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
|
||||
|
||||
@@ -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(',')
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ export function match<TValue extends string | number = string, TReturnValue = un
|
||||
`Tried to handle "${value}" but there is no handler defined. Only defined handlers are: ${Object.keys(
|
||||
lookup
|
||||
)
|
||||
.map(key => `"${key}"`)
|
||||
.map((key) => `"${key}"`)
|
||||
.join(', ')}.`
|
||||
)
|
||||
if (Error.captureStackTrace) Error.captureStackTrace(error, match)
|
||||
|
||||
@@ -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<Parameters<typeof defineComponent>[0]>) {
|
||||
function renderTemplate(input: string | ComponentOptionsWithoutProps) {
|
||||
let defaultComponents = { Dummy }
|
||||
|
||||
if (typeof input === 'string') {
|
||||
@@ -34,9 +34,7 @@ describe('Validation', () => {
|
||||
expect.hasAssertions()
|
||||
|
||||
renderTemplate({
|
||||
template: html`
|
||||
<Dummy as="template" class="abc">Contents</Dummy>
|
||||
`,
|
||||
template: html` <Dummy as="template" class="abc">Contents</Dummy> `,
|
||||
errorCaptured(err) {
|
||||
expect(err as Error).toEqual(
|
||||
new Error(
|
||||
|
||||
@@ -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')
|
||||
)
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noEmit": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true
|
||||
},
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user