diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index ddc20f2d84..fc2d525bcd 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -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. - diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index fbdfa1eeb7..347a88b719 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -12,4 +12,3 @@ contact_links: - name: Documentation Issue url: https://github.com/tailwindlabs/headlessui/issues/new?title=%5BDOCS%5D:%20 about: 'For documentation issues, suggest changes on our documentation repository.' - diff --git a/.github/workflows/release-insiders.yml b/.github/workflows/release-insiders.yml index b7bbc85525..e6891facb4 100644 --- a/.github/workflows/release-insiders.yml +++ b/.github/workflows/release-insiders.yml @@ -44,7 +44,7 @@ jobs: id: vars run: echo "::set-output name=sha_short::$(git rev-parse --short HEAD)" - - name: "Version based on commit: 0.0.0-insiders.${{ steps.vars.outputs.sha_short }}" + - name: 'Version based on commit: 0.0.0-insiders.${{ steps.vars.outputs.sha_short }}' run: npm version -w packages 0.0.0-insiders.${{ steps.vars.outputs.sha_short }} --force --no-git-tag-version - name: Publish @@ -52,4 +52,3 @@ jobs: env: CI: true NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000000..62815c2732 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,4 @@ +dist/ +node_modules/ +coverage/ +.next/ diff --git a/.swcrc b/.swcrc new file mode 100644 index 0000000000..0c4dc7af87 --- /dev/null +++ b/.swcrc @@ -0,0 +1,11 @@ +{ + "minify": false, + "jsc": { + "parser": { + "syntax": "typescript", + "tsx": true, + "decorators": false, + "dynamicImport": false + } + } +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 46dedd4452..e02468b748 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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)) diff --git a/README.md b/README.md index 30a518bf84..5f42a558a9 100644 --- a/README.md +++ b/README.md @@ -49,4 +49,3 @@ For casual chit-chat with others using the library: ## Contributing If you're interested in contributing to Headless UI, please read our [contributing docs](https://github.com/tailwindlabs/headlessui/blob/main/.github/CONTRIBUTING.md) **before submitting a pull request**. - diff --git a/jest/create-jest-config.js b/jest/create-jest-config.js index 5cbedca808..bbeb0b88a0 100644 --- a/jest/create-jest-config.js +++ b/jest/create-jest-config.js @@ -1,17 +1,10 @@ -const { createJestConfig: create } = require('tsdx/dist/createJestConfig') - module.exports = function createJestConfig(root, options) { return Object.assign( - {}, - create(undefined, root), { rootDir: root, setupFilesAfterEnv: ['../../jest/custom-matchers.ts'], - globals: { - 'ts-jest': { - isolatedModules: true, - tsConfig: '/tsconfig.tsdx.json', - }, + transform: { + '^.+\\.(t|j)sx?$': '@swc/jest', }, }, options diff --git a/package.json b/package.json index 7f6b020967..120d84e4ca 100644 --- a/package.json +++ b/package.json @@ -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" } } diff --git a/packages/@headlessui-react/README.md b/packages/@headlessui-react/README.md index fa2a630f49..733df5c86a 100644 --- a/packages/@headlessui-react/README.md +++ b/packages/@headlessui-react/README.md @@ -36,4 +36,3 @@ For help, discussion about best practices, or any other conversation that would For casual chit-chat with others using the library: [Join the Tailwind CSS Discord Server](https://discord.gg/7NF8GNe) - diff --git a/packages/@headlessui-react/build/index.js b/packages/@headlessui-react/build/index.js new file mode 100644 index 0000000000..473f46702e --- /dev/null +++ b/packages/@headlessui-react/build/index.js @@ -0,0 +1,7 @@ +'use strict' + +if (process.env.NODE_ENV === 'production') { + module.exports = require('./headlessui.prod.cjs.js') +} else { + module.exports = require('./headlessui.dev.cjs.js') +} diff --git a/packages/@headlessui-react/package.json b/packages/@headlessui-react/package.json index a638b2d81a..63d805cfe5 100644 --- a/packages/@headlessui-react/package.json +++ b/packages/@headlessui-react/package.json @@ -4,12 +4,21 @@ "description": "A set of completely unstyled, fully accessible UI components for React, designed to integrate beautifully with Tailwind CSS.", "main": "dist/index.js", "typings": "dist/index.d.ts", - "module": "dist/index.esm.js", + "module": "dist/headlessui.esm.js", "license": "MIT", "files": [ "README.md", "dist" ], + "exports": { + ".": { + "import": { + "default": "./dist/headlessui.esm.js" + }, + "require": "./dist/index.js", + "types": "./dist/index.d.ts" + } + }, "sideEffects": false, "engines": { "node": ">=10" @@ -24,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" } } diff --git a/packages/@headlessui-react/src/components/combobox/combobox.test.tsx b/packages/@headlessui-react/src/components/combobox/combobox.test.tsx index 60c6375b12..e5f79c50fc 100644 --- a/packages/@headlessui-react/src/components/combobox/combobox.test.tsx +++ b/packages/@headlessui-react/src/components/combobox/combobox.test.tsx @@ -481,7 +481,7 @@ describe('Rendering', () => { Trigger - {data => ( + {(data) => ( <> {JSON.stringify(data)} @@ -639,10 +639,10 @@ describe('Rendering composition', () => { Trigger - JSON.stringify(bag)}> + JSON.stringify(bag)}> Option A - JSON.stringify(bag)}> + JSON.stringify(bag)}> Option B @@ -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', () => { - {data => ( + {(data) => ( <> {JSON.stringify(data)} @@ -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', () => { Trigger - {myOptions.map(myOption => ( + {myOptions.map((myOption) => ( {myOption.name} @@ -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 ( { + 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 ( - setQuery(event.target.value)} /> + setQuery(event.target.value)} /> Trigger - {filteredPeople.map(person => ( + {filteredPeople.map((person) => ( {person.name} @@ -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 ( { + onChange={(value) => { setValue(value) handleChange(value) }} @@ -4804,7 +4806,7 @@ describe('Mouse interactions', () => { return ( { + onChange={(value) => { setValue(value) handleChange(value) }} diff --git a/packages/@headlessui-react/src/components/combobox/combobox.tsx b/packages/@headlessui-react/src/components/combobox/combobox.tsx index d0f327b940..614113221a 100644 --- a/packages/@headlessui-react/src/components/combobox/combobox.tsx +++ b/packages/@headlessui-react/src/components/combobox/combobox.tsx @@ -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 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 { - 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 ) { 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, ref: Ref ) { - 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( props: Props ) { - 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( () => ({ open: state.comboboxState === ComboboxStates.Open, disabled: state.disabled }), @@ -737,7 +739,7 @@ let Options = forwardRefWithAs(function Options< PropsForFeatures, ref: Ref ) { - 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(() => ({ active, selected, disabled }), [ - active, - selected, - disabled, - ]) + let slot = useMemo( + () => ({ active, selected, disabled }), + [active, selected, disabled] + ) let propsWeControl = { id, diff --git a/packages/@headlessui-react/src/components/description/description.tsx b/packages/@headlessui-react/src/components/description/description.tsx index 716a9b2813..b0dc312e2b 100644 --- a/packages/@headlessui-react/src/components/description/description.tsx +++ b/packages/@headlessui-react/src/components/description/description.tsx @@ -57,10 +57,10 @@ export function useDescriptions(): [ useMemo(() => { return function DescriptionProvider(props: DescriptionProviderProps) { let register = useCallback((value: string) => { - setDescriptionIds(existing => [...existing, value]) + setDescriptionIds((existing) => [...existing, value]) return () => - setDescriptionIds(existing => { + setDescriptionIds((existing) => { let clone = existing.slice() let idx = clone.indexOf(value) if (idx !== -1) clone.splice(idx, 1) diff --git a/packages/@headlessui-react/src/components/dialog/dialog.test.tsx b/packages/@headlessui-react/src/components/dialog/dialog.test.tsx index 4a07169dd0..908023b600 100644 --- a/packages/@headlessui-react/src/components/dialog/dialog.test.tsx +++ b/packages/@headlessui-react/src/components/dialog/dialog.test.tsx @@ -143,7 +143,7 @@ describe('Rendering', () => { Trigger - {data => ( + {(data) => ( <>
{JSON.stringify(data)}
@@ -204,7 +204,7 @@ describe('Rendering', () => { return ( <> - @@ -239,7 +239,7 @@ describe('Rendering', () => { return ( <> - @@ -277,7 +277,7 @@ describe('Rendering', () => { let [isOpen, setIsOpen] = useState(false) return ( <> - @@ -400,7 +400,7 @@ describe('Keyboard interactions', () => { let [isOpen, setIsOpen] = useState(false) return ( <> - @@ -438,7 +438,7 @@ describe('Keyboard interactions', () => { let [isOpen, setIsOpen] = useState(false) return ( <> - @@ -477,14 +477,14 @@ describe('Keyboard interactions', () => { let [isOpen, setIsOpen] = useState(false) return ( <> - Contents { + onKeyDown={(event) => { event.preventDefault() event.stopPropagation() }} @@ -525,7 +525,7 @@ describe('Mouse interactions', () => { let [isOpen, setIsOpen] = useState(false) return ( <> - @@ -559,7 +559,7 @@ describe('Mouse interactions', () => { let [isOpen, setIsOpen] = useState(false) return ( <> - @@ -595,7 +595,7 @@ describe('Mouse interactions', () => { let [isOpen, setIsOpen] = useState(false) return ( <> - + Contents @@ -630,7 +630,7 @@ describe('Mouse interactions', () => { return ( <> - + Contents diff --git a/packages/@headlessui-react/src/components/dialog/dialog.tsx b/packages/@headlessui-react/src/components/dialog/dialog.tsx index aa62837ac1..edf3e3a0fb 100644 --- a/packages/@headlessui-react/src/components/dialog/dialog.tsx +++ b/packages/@headlessui-react/src/components/dialog/dialog.tsx @@ -206,7 +206,7 @@ let DialogRoot = forwardRefWithAs(function Dialog< useInertOthers(internalDialogRef, hasNestedDialogs ? enabled : false) // Handle outside click - useWindowEvent('mousedown', event => { + useWindowEvent('mousedown', (event) => { let target = event.target as HTMLElement if (dialogState !== DialogStates.Open) return @@ -217,7 +217,7 @@ let DialogRoot = forwardRefWithAs(function Dialog< }) // Handle `Escape` to close - useWindowEvent('keydown', event => { + useWindowEvent('keydown', (event) => { if (event.key !== Keys.Escape) return if (dialogState !== DialogStates.Open) return if (hasNestedDialogs) return @@ -250,7 +250,7 @@ let DialogRoot = forwardRefWithAs(function Dialog< if (dialogState !== DialogStates.Open) return if (!internalDialogRef.current) return - let observer = new IntersectionObserver(entries => { + let observer = new IntersectionObserver((entries) => { for (let entry of entries) { if ( entry.boundingClientRect.x === 0 && @@ -277,9 +277,10 @@ let DialogRoot = forwardRefWithAs(function Dialog< [dialogState, state, close, setTitleId] ) - let slot = useMemo(() => ({ open: dialogState === DialogStates.Open }), [ - dialogState, - ]) + let slot = useMemo( + () => ({ open: dialogState === DialogStates.Open }), + [dialogState] + ) let propsWeControl = { ref: dialogRef, @@ -304,11 +305,11 @@ let DialogRoot = forwardRefWithAs(function Dialog< match(message, { [StackMessage.Add]() { containers.current.add(element) - setNestedDialogCount(count => count + 1) + setNestedDialogCount((count) => count + 1) }, [StackMessage.Remove]() { containers.current.add(element) - setNestedDialogCount(count => count - 1) + setNestedDialogCount((count) => count - 1) }, }) }, [])} @@ -348,7 +349,7 @@ type OverlayPropsWeControl = 'id' | 'aria-hidden' | 'onClick' let Overlay = forwardRefWithAs(function Overlay< TTag extends ElementType = typeof DEFAULT_OVERLAY_TAG >(props: Props, ref: Ref) { - let [{ dialogState, close }] = useDialogContext([Dialog.displayName, Overlay.name].join('.')) + let [{ dialogState, close }] = useDialogContext('Dialog.Overlay') let overlayRef = useSyncRefs(ref) let id = `headlessui-dialog-overlay-${useId()}` @@ -364,9 +365,10 @@ let Overlay = forwardRefWithAs(function Overlay< [close] ) - let slot = useMemo(() => ({ open: dialogState === DialogStates.Open }), [ - dialogState, - ]) + let slot = useMemo( + () => ({ open: dialogState === DialogStates.Open }), + [dialogState] + ) let propsWeControl = { ref: overlayRef, id, @@ -394,7 +396,7 @@ type TitlePropsWeControl = 'id' function Title( props: Props ) { - let [{ dialogState, setTitleId }] = useDialogContext([Dialog.displayName, Title.name].join('.')) + let [{ dialogState, setTitleId }] = useDialogContext('Dialog.Title') let id = `headlessui-dialog-title-${useId()}` @@ -403,9 +405,10 @@ function Title( return () => setTitleId(null) }, [id, setTitleId]) - let slot = useMemo(() => ({ open: dialogState === DialogStates.Open }), [ - dialogState, - ]) + let slot = useMemo( + () => ({ open: dialogState === DialogStates.Open }), + [dialogState] + ) let propsWeControl = { id } let passthroughProps = props diff --git a/packages/@headlessui-react/src/components/disclosure/disclosure.test.tsx b/packages/@headlessui-react/src/components/disclosure/disclosure.test.tsx index 6c72cff4e1..1d93d260b5 100644 --- a/packages/@headlessui-react/src/components/disclosure/disclosure.test.tsx +++ b/packages/@headlessui-react/src/components/disclosure/disclosure.test.tsx @@ -20,7 +20,7 @@ jest.mock('../../hooks/use-id') afterAll(() => jest.restoreAllMocks()) function nextFrame() { - return new Promise(resolve => { + return new Promise((resolve) => { requestAnimationFrame(() => { requestAnimationFrame(() => { resolve() diff --git a/packages/@headlessui-react/src/components/disclosure/disclosure.tsx b/packages/@headlessui-react/src/components/disclosure/disclosure.tsx index 587df365f0..5dcd19b609 100644 --- a/packages/@headlessui-react/src/components/disclosure/disclosure.tsx +++ b/packages/@headlessui-react/src/components/disclosure/disclosure.tsx @@ -68,14 +68,14 @@ let reducers: { action: Extract ) => StateDefinition } = { - [ActionTypes.ToggleDisclosure]: state => ({ + [ActionTypes.ToggleDisclosure]: (state) => ({ ...state, disclosureState: match(state.disclosureState, { [DisclosureStates.Open]: DisclosureStates.Closed, [DisclosureStates.Closed]: DisclosureStates.Open, }), }), - [ActionTypes.CloseDisclosure]: state => { + [ActionTypes.CloseDisclosure]: (state) => { if (state.disclosureState === DisclosureStates.Closed) return state return { ...state, disclosureState: DisclosureStates.Closed } }, @@ -227,7 +227,7 @@ let Button = forwardRefWithAs(function Button, ref: Ref ) { - let [state, dispatch] = useDisclosureContext([Disclosure.name, Button.name].join('.')) + let [state, dispatch] = useDisclosureContext('Disclosure.Button') let internalButtonRef = useRef(null) let buttonRef = useSyncRefs(internalButtonRef, ref) @@ -334,8 +334,8 @@ let Panel = forwardRefWithAs(function Panel, ref: Ref ) { - let [state, dispatch] = useDisclosureContext([Disclosure.name, Panel.name].join('.')) - let { close } = useDisclosureAPIContext([Disclosure.name, Panel.name].join('.')) + let [state, dispatch] = useDisclosureContext('Disclosure.Panel') + let { close } = useDisclosureAPIContext('Disclosure.Panel') let panelRef = useSyncRefs(ref, () => { if (state.linkedPanel) return diff --git a/packages/@headlessui-react/src/components/label/label.tsx b/packages/@headlessui-react/src/components/label/label.tsx index 0d23754556..871ef93c6b 100644 --- a/packages/@headlessui-react/src/components/label/label.tsx +++ b/packages/@headlessui-react/src/components/label/label.tsx @@ -52,10 +52,10 @@ export function useLabels(): [string | undefined, (props: LabelProviderProps) => useMemo(() => { return function LabelProvider(props: LabelProviderProps) { let register = useCallback((value: string) => { - setLabelIds(existing => [...existing, value]) + setLabelIds((existing) => [...existing, value]) return () => - setLabelIds(existing => { + setLabelIds((existing) => { let clone = existing.slice() let idx = clone.indexOf(value) if (idx !== -1) clone.splice(idx, 1) diff --git a/packages/@headlessui-react/src/components/listbox/listbox.test.tsx b/packages/@headlessui-react/src/components/listbox/listbox.test.tsx index 90011989f2..eea9fc118c 100644 --- a/packages/@headlessui-react/src/components/listbox/listbox.test.tsx +++ b/packages/@headlessui-react/src/components/listbox/listbox.test.tsx @@ -56,6 +56,7 @@ describe('safeguards', () => { ])( 'should error when we are using a <%s /> without a parent ', suppressConsoleLogs((name, Component) => { + // @ts-expect-error This is fine expect(() => render(createElement(Component))).toThrowError( `<${name} /> is missing a parent component.` ) @@ -396,7 +397,7 @@ describe('Rendering', () => { Trigger - {data => ( + {(data) => ( <> {JSON.stringify(data)} @@ -547,10 +548,10 @@ describe('Rendering composition', () => { Trigger - JSON.stringify(bag)}> + JSON.stringify(bag)}> Option A - JSON.stringify(bag)}> + JSON.stringify(bag)}> Option B @@ -645,7 +646,7 @@ describe('Rendering composition', () => { await click(getListboxButton()) // Verify options are buttons now - getListboxOptions().forEach(option => assertListboxOption(option, { tag: 'button' })) + getListboxOptions().forEach((option) => assertListboxOption(option, { tag: 'button' })) }) ) }) @@ -673,7 +674,7 @@ describe('Composition', () => { - {data => ( + {(data) => ( <> {JSON.stringify(data)} @@ -756,7 +757,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option, { selected: false })) + options.forEach((option) => assertListboxOption(option, { selected: false })) // Verify that the first listbox option is active assertActiveListboxOption(options[0]) @@ -918,7 +919,7 @@ describe('Keyboard interactions', () => { Trigger - {myOptions.map(myOption => ( + {myOptions.map((myOption) => ( {myOption.name} @@ -1139,7 +1140,7 @@ describe('Keyboard interactions', () => { return ( { + onChange={(value) => { setValue(value) handleChange(value) }} @@ -1234,7 +1235,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[0]) }) ) @@ -1462,7 +1463,7 @@ describe('Keyboard interactions', () => { return ( { + onChange={(value) => { setValue(value) handleChange(value) }} @@ -1600,7 +1601,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[0]) // Try to tab @@ -1651,7 +1652,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[0]) // Try to Shift+Tab @@ -1704,7 +1705,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) // Verify that the first listbox option is active assertActiveListboxOption(options[0]) @@ -1844,7 +1845,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[0]) // We should be able to go down once @@ -1892,7 +1893,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[1]) // We should be able to go down once @@ -1934,7 +1935,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[2]) }) ) @@ -1970,7 +1971,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[0]) // We should be able to go right once @@ -2027,7 +2028,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) // ! ALERT: The LAST option should now be active assertActiveListboxOption(options[2]) @@ -2171,7 +2172,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[0]) }) ) @@ -2209,7 +2210,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[2]) // We should not be able to go up (because those are disabled) @@ -2260,7 +2261,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[2]) // We should be able to go down once @@ -2318,7 +2319,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[2]) // We should be able to go left once @@ -3198,7 +3199,7 @@ describe('Mouse interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) }) ) @@ -3726,7 +3727,7 @@ describe('Mouse interactions', () => { return ( { + onChange={(value) => { setValue(value) handleChange(value) }} @@ -3777,7 +3778,7 @@ describe('Mouse interactions', () => { return ( { + onChange={(value) => { setValue(value) handleChange(value) }} diff --git a/packages/@headlessui-react/src/components/listbox/listbox.tsx b/packages/@headlessui-react/src/components/listbox/listbox.tsx index 26432b85b4..da2741cef6 100644 --- a/packages/@headlessui-react/src/components/listbox/listbox.tsx +++ b/packages/@headlessui-react/src/components/listbox/listbox.tsx @@ -119,8 +119,8 @@ let reducers: { let activeOptionIndex = calculateActiveIndex(action, { resolveItems: () => state.options, resolveActiveIndex: () => state.activeOptionIndex, - resolveId: item => item.id, - resolveDisabled: item => item.dataRef.current.disabled, + resolveId: (item) => item.id, + resolveDisabled: (item) => item.dataRef.current.disabled, }) if (state.searchQuery === '' && state.activeOptionIndex === activeOptionIndex) return state @@ -140,7 +140,7 @@ let reducers: { : state.options let matchingOption = reOrderedOptions.find( - option => + (option) => !option.dataRef.current.disabled && option.dataRef.current.textValue?.startsWith(searchQuery) ) @@ -175,7 +175,7 @@ let reducers: { let currentActiveOption = state.activeOptionIndex !== null ? nextOptions[state.activeOptionIndex] : null - let idx = nextOptions.findIndex(a => a.id === action.id) + let idx = nextOptions.findIndex((a) => a.id === action.id) if (idx !== -1) nextOptions.splice(idx, 1) @@ -251,12 +251,13 @@ export function Listbox dispatch({ type: ActionTypes.SetDisabled, disabled }), [disabled]) - useIsoMorphicEffect(() => dispatch({ type: ActionTypes.SetOrientation, orientation }), [ - orientation, - ]) + useIsoMorphicEffect( + () => dispatch({ type: ActionTypes.SetOrientation, orientation }), + [orientation] + ) // Handle outside click - useWindowEvent('mousedown', event => { + useWindowEvent('mousedown', (event) => { let target = event.target as HTMLElement if (listboxState !== ListboxStates.Open) return @@ -318,7 +319,7 @@ let Button = forwardRefWithAs(function Button, ref: Ref ) { - let [state, dispatch] = useListboxContext([Listbox.name, Button.name].join('.')) + let [state, dispatch] = useListboxContext('Listbox.Button') let buttonRef = useSyncRefs(state.buttonRef, ref) let id = `headlessui-listbox-button-${useId()}` @@ -422,12 +423,13 @@ type LabelPropsWeControl = 'id' | 'ref' | 'onClick' function Label( props: Props ) { - let [state] = useListboxContext([Listbox.name, Label.name].join('.')) + let [state] = useListboxContext('Listbox.Label') let id = `headlessui-listbox-label-${useId()}` - let handleClick = useCallback(() => state.buttonRef.current?.focus({ preventScroll: true }), [ - state.buttonRef, - ]) + let handleClick = useCallback( + () => state.buttonRef.current?.focus({ preventScroll: true }), + [state.buttonRef] + ) let slot = useMemo( () => ({ open: state.listboxState === ListboxStates.Open, disabled: state.disabled }), @@ -466,7 +468,7 @@ let Options = forwardRefWithAs(function Options< PropsForFeatures, ref: Ref ) { - let [state, dispatch] = useListboxContext([Listbox.name, Options.name].join('.')) + let [state, dispatch] = useListboxContext('Listbox.Options') let optionsRef = useSyncRefs(state.optionsRef, ref) let id = `headlessui-listbox-options-${useId()}` @@ -561,10 +563,10 @@ let Options = forwardRefWithAs(function Options< [d, dispatch, searchDisposables, state] ) - let labelledby = useComputed(() => state.labelRef.current?.id ?? state.buttonRef.current?.id, [ - state.labelRef.current, - state.buttonRef.current, - ]) + let labelledby = useComputed( + () => state.labelRef.current?.id ?? state.buttonRef.current?.id, + [state.labelRef.current, state.buttonRef.current] + ) let slot = useMemo( () => ({ open: state.listboxState === ListboxStates.Open }), @@ -625,7 +627,7 @@ function Option< } ) { let { disabled = false, value, ...passthroughProps } = props - let [state, dispatch] = useListboxContext([Listbox.name, Option.name].join('.')) + let [state, dispatch] = useListboxContext('Listbox.Option') let id = `headlessui-listbox-option-${useId()}` let active = state.activeOptionIndex !== null ? state.options[state.activeOptionIndex].id === id : false @@ -692,11 +694,10 @@ function Option< dispatch({ type: ActionTypes.GoToOption, focus: Focus.Nothing }) }, [disabled, active, dispatch]) - let slot = useMemo(() => ({ active, selected, disabled }), [ - active, - selected, - disabled, - ]) + let slot = useMemo( + () => ({ active, selected, disabled }), + [active, selected, disabled] + ) let propsWeControl = { id, role: 'option', diff --git a/packages/@headlessui-react/src/components/menu/menu.test.tsx b/packages/@headlessui-react/src/components/menu/menu.test.tsx index a5a2a9b67c..1fc853d9b6 100644 --- a/packages/@headlessui-react/src/components/menu/menu.test.tsx +++ b/packages/@headlessui-react/src/components/menu/menu.test.tsx @@ -253,7 +253,7 @@ describe('Rendering', () => { Trigger - {data => ( + {(data) => ( <> {JSON.stringify(data)} @@ -403,10 +403,10 @@ describe('Rendering composition', () => { Trigger - JSON.stringify(bag)}> + JSON.stringify(bag)}> Item A - JSON.stringify(bag)}> + JSON.stringify(bag)}> Item B @@ -484,7 +484,7 @@ describe('Rendering composition', () => { // Verify items are buttons now let items = getMenuItems() - items.forEach(item => assertMenuItem(item, { tag: 'button' })) + items.forEach((item) => assertMenuItem(item, { tag: 'button' })) }) ) @@ -496,11 +496,11 @@ describe('Rendering composition', () => { Trigger
-
+
Item A Item B
-
+
Item C
@@ -508,7 +508,7 @@ describe('Rendering composition', () => {
-
+
Item E
@@ -523,11 +523,11 @@ describe('Rendering composition', () => { expect.hasAssertions() - document.querySelectorAll('.outer').forEach(element => { + document.querySelectorAll('.outer').forEach((element) => { expect(element).not.toHaveAttribute('role', 'none') }) - document.querySelectorAll('.inner').forEach(element => { + document.querySelectorAll('.inner').forEach((element) => { expect(element).toHaveAttribute('role', 'none') }) }) @@ -557,7 +557,7 @@ describe('Composition', () => { - {data => ( + {(data) => ( <> {JSON.stringify(data)} @@ -611,7 +611,7 @@ describe('Composition', () => { - {data => ( + {(data) => ( <> {JSON.stringify(data)} @@ -693,7 +693,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) // Verify that the first menu item is active assertMenuLinkedWithMenuItem(items[0]) @@ -1057,7 +1057,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) assertMenuLinkedWithMenuItem(items[0]) }) ) @@ -1395,7 +1395,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) assertMenuLinkedWithMenuItem(items[0]) // Try to tab @@ -1444,7 +1444,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) assertMenuLinkedWithMenuItem(items[0]) // Try to Shift+Tab @@ -1495,7 +1495,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) // Verify that the first menu item is active assertMenuLinkedWithMenuItem(items[0]) @@ -1589,7 +1589,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) assertMenuLinkedWithMenuItem(items[0]) // We should be able to go down once @@ -1637,7 +1637,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) assertMenuLinkedWithMenuItem(items[1]) // We should be able to go down once @@ -1679,7 +1679,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) assertMenuLinkedWithMenuItem(items[2]) }) ) @@ -1723,7 +1723,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) // ! ALERT: The LAST item should now be active assertMenuLinkedWithMenuItem(items[2]) @@ -1821,7 +1821,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) assertMenuLinkedWithMenuItem(items[0]) }) ) @@ -1859,7 +1859,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) assertMenuLinkedWithMenuItem(items[2]) // We should not be able to go up (because those are disabled) @@ -1909,7 +1909,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) assertMenuLinkedWithMenuItem(items[2]) // We should be able to go down once @@ -2736,7 +2736,7 @@ describe('Mouse interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) }) ) diff --git a/packages/@headlessui-react/src/components/menu/menu.tsx b/packages/@headlessui-react/src/components/menu/menu.tsx index 3e871fe15a..962549fdf6 100644 --- a/packages/@headlessui-react/src/components/menu/menu.tsx +++ b/packages/@headlessui-react/src/components/menu/menu.tsx @@ -91,8 +91,8 @@ let reducers: { let activeItemIndex = calculateActiveIndex(action, { resolveItems: () => state.items, resolveActiveIndex: () => state.activeItemIndex, - resolveId: item => item.id, - resolveDisabled: item => item.dataRef.current.disabled, + resolveId: (item) => item.id, + resolveDisabled: (item) => item.dataRef.current.disabled, }) if (state.searchQuery === '' && state.activeItemIndex === activeItemIndex) return state @@ -109,7 +109,7 @@ let reducers: { : state.items let matchingItem = reOrderedItems.find( - item => + (item) => item.dataRef.current.textValue?.startsWith(searchQuery) && !item.dataRef.current.disabled ) @@ -139,7 +139,7 @@ let reducers: { let nextItems = state.items.slice() let currentActiveItem = state.activeItemIndex !== null ? nextItems[state.activeItemIndex] : null - let idx = nextItems.findIndex(a => a.id === action.id) + let idx = nextItems.findIndex((a) => a.id === action.id) if (idx !== -1) nextItems.splice(idx, 1) @@ -196,7 +196,7 @@ export function Menu( let [{ menuState, itemsRef, buttonRef }, dispatch] = reducerBag // Handle outside click - useWindowEvent('mousedown', event => { + useWindowEvent('mousedown', (event) => { let target = event.target as HTMLElement if (menuState !== MenuStates.Open) return @@ -212,9 +212,10 @@ export function Menu( } }) - let slot = useMemo(() => ({ open: menuState === MenuStates.Open }), [ - menuState, - ]) + let slot = useMemo( + () => ({ open: menuState === MenuStates.Open }), + [menuState] + ) return ( @@ -249,7 +250,7 @@ let Button = forwardRefWithAs(function Button, ref: Ref ) { - let [state, dispatch] = useMenuContext([Menu.name, Button.name].join('.')) + let [state, dispatch] = useMenuContext('Menu.Button') let buttonRef = useSyncRefs(state.buttonRef, ref) let id = `headlessui-menu-button-${useId()}` @@ -307,9 +308,10 @@ let Button = forwardRefWithAs(function Button(() => ({ open: state.menuState === MenuStates.Open }), [ - state, - ]) + let slot = useMemo( + () => ({ open: state.menuState === MenuStates.Open }), + [state] + ) let passthroughProps = props let propsWeControl = { ref: buttonRef, @@ -352,7 +354,7 @@ let Items = forwardRefWithAs(function Items, ref: Ref ) { - let [state, dispatch] = useMenuContext([Menu.name, Items.name].join('.')) + let [state, dispatch] = useMenuContext('Menu.Items') let itemsRef = useSyncRefs(state.itemsRef, ref) let id = `headlessui-menu-items-${useId()}` @@ -471,9 +473,10 @@ let Items = forwardRefWithAs(function Items(() => ({ open: state.menuState === MenuStates.Open }), [ - state, - ]) + let slot = useMemo( + () => ({ open: state.menuState === MenuStates.Open }), + [state] + ) let propsWeControl = { 'aria-activedescendant': state.activeItemIndex === null ? undefined : state.items[state.activeItemIndex]?.id, @@ -522,7 +525,7 @@ function Item( } ) { let { disabled = false, onClick, ...passthroughProps } = props - let [state, dispatch] = useMenuContext([Menu.name, Item.name].join('.')) + let [state, dispatch] = useMenuContext('Menu.Item') let id = `headlessui-menu-item-${useId()}` let active = state.activeItemIndex !== null ? state.items[state.activeItemIndex].id === id : false diff --git a/packages/@headlessui-react/src/components/popover/popover.test.tsx b/packages/@headlessui-react/src/components/popover/popover.test.tsx index c39fc8a43a..f8f73a2d00 100644 --- a/packages/@headlessui-react/src/components/popover/popover.test.tsx +++ b/packages/@headlessui-react/src/components/popover/popover.test.tsx @@ -23,7 +23,7 @@ jest.mock('../../hooks/use-id') afterAll(() => jest.restoreAllMocks()) function nextFrame() { - return new Promise(resolve => { + return new Promise((resolve) => { requestAnimationFrame(() => { requestAnimationFrame(() => { resolve() diff --git a/packages/@headlessui-react/src/components/popover/popover.tsx b/packages/@headlessui-react/src/components/popover/popover.tsx index f0e7264543..779a122917 100644 --- a/packages/@headlessui-react/src/components/popover/popover.tsx +++ b/packages/@headlessui-react/src/components/popover/popover.tsx @@ -75,7 +75,7 @@ let reducers: { action: Extract ) => StateDefinition } = { - [ActionTypes.TogglePopover]: state => ({ + [ActionTypes.TogglePopover]: (state) => ({ ...state, popoverState: match(state.popoverState, { [PopoverStates.Open]: PopoverStates.Closed, @@ -217,7 +217,7 @@ export function Popover( ) // Handle outside click - useWindowEvent('mousedown', event => { + useWindowEvent('mousedown', (event) => { let target = event.target as HTMLElement if (popoverState !== PopoverStates.Open) return @@ -296,7 +296,7 @@ let Button = forwardRefWithAs(function Button, ref: Ref ) { - let [state, dispatch] = usePopoverContext([Popover.name, Button.name].join('.')) + let [state, dispatch] = usePopoverContext('Popover.Button') let internalButtonRef = useRef(null) let groupContext = usePopoverGroupContext() @@ -308,7 +308,7 @@ let Button = forwardRefWithAs(function Button dispatch({ type: ActionTypes.SetButton, button }) + isWithinPanel ? null : (button) => dispatch({ type: ActionTypes.SetButton, button }) ) let withinPanelButtonRef = useSyncRefs(internalButtonRef, ref) @@ -517,7 +517,7 @@ let Overlay = forwardRefWithAs(function Overlay< PropsForFeatures, ref: Ref ) { - let [{ popoverState }, dispatch] = usePopoverContext([Popover.name, Overlay.name].join('.')) + let [{ popoverState }, dispatch] = usePopoverContext('Popover.Overlay') let overlayRef = useSyncRefs(ref) let id = `headlessui-popover-overlay-${useId()}` @@ -539,9 +539,10 @@ let Overlay = forwardRefWithAs(function Overlay< [dispatch] ) - let slot = useMemo(() => ({ open: popoverState === PopoverStates.Open }), [ - popoverState, - ]) + let slot = useMemo( + () => ({ open: popoverState === PopoverStates.Open }), + [popoverState] + ) let propsWeControl = { ref: overlayRef, id, @@ -580,11 +581,11 @@ let Panel = forwardRefWithAs(function Panel(null) - let panelRef = useSyncRefs(internalPanelRef, ref, panel => { + let panelRef = useSyncRefs(internalPanelRef, ref, (panel) => { dispatch({ type: ActionTypes.SetPanel, panel }) }) @@ -639,7 +640,7 @@ let Panel = forwardRefWithAs(function Panel { + useWindowEvent('keydown', (event) => { if (state.popoverState !== PopoverStates.Open) return if (!internalPanelRef.current) return if (event.key !== Keys.Tab) return @@ -665,7 +666,7 @@ let Panel = forwardRefWithAs(function Panel !internalPanelRef.current?.contains(element)) // Ignore items in panel + .filter((element) => !internalPanelRef.current?.contains(element)) // Ignore items in panel // Try to focus the next element, however it could fail if we are in a // Portal that happens to be the very last one in the DOM. In that @@ -730,7 +731,7 @@ function Group( let unregisterPopover = useCallback( (registerbag: PopoverRegisterBag) => { - setPopovers(existing => { + setPopovers((existing) => { let idx = existing.indexOf(registerbag) if (idx !== -1) { let clone = existing.slice() @@ -745,7 +746,7 @@ function Group( let registerPopover = useCallback( (registerbag: PopoverRegisterBag) => { - setPopovers(existing => [...existing, registerbag]) + setPopovers((existing) => [...existing, registerbag]) return () => unregisterPopover(registerbag) }, [setPopovers, unregisterPopover] @@ -757,7 +758,7 @@ function Group( if (groupRef.current?.contains(element)) return true // Check if the focus is in one of the button or panel elements. This is important in case you are rendering inside a Portal. - return popovers.some(bag => { + return popovers.some((bag) => { return ( document.getElementById(bag.buttonId)?.contains(element) || document.getElementById(bag.panelId)?.contains(element) diff --git a/packages/@headlessui-react/src/components/portal/portal.test.tsx b/packages/@headlessui-react/src/components/portal/portal.test.tsx index eea7c4cb06..6b21ea7a5c 100644 --- a/packages/@headlessui-react/src/components/portal/portal.test.tsx +++ b/packages/@headlessui-react/src/components/portal/portal.test.tsx @@ -82,10 +82,10 @@ it('should cleanup the Portal root when the last Portal is unmounted', async () return (
- - @@ -151,21 +151,21 @@ it('should be possible to render multiple portals at the same time', async () => return (
- - - - diff --git a/packages/@headlessui-react/src/components/radio-group/radio-group.test.tsx b/packages/@headlessui-react/src/components/radio-group/radio-group.test.tsx index f9f7076c70..010602e64f 100644 --- a/packages/@headlessui-react/src/components/radio-group/radio-group.test.tsx +++ b/packages/@headlessui-react/src/components/radio-group/radio-group.test.tsx @@ -113,7 +113,7 @@ describe('Rendering', () => { return ( <> - + Pizza Delivery {showFirst && Pickup} @@ -145,7 +145,7 @@ describe('Rendering', () => { let [disabled, setDisabled] = useState(true) return ( <> - + Pizza Delivery Pickup @@ -208,7 +208,7 @@ describe('Rendering', () => { let [disabled, setDisabled] = useState(true) return ( <> - + Pizza Delivery Pickup @@ -745,7 +745,7 @@ describe('Keyboard interactions', () => { { + onChange={(v) => { setValue(v) changeFn(v) }} @@ -815,7 +815,7 @@ describe('Mouse interactions', () => { { + onChange={(v) => { setValue(v) changeFn(v) }} diff --git a/packages/@headlessui-react/src/components/radio-group/radio-group.tsx b/packages/@headlessui-react/src/components/radio-group/radio-group.tsx index b65bb64a8a..3c81a9e9a2 100644 --- a/packages/@headlessui-react/src/components/radio-group/radio-group.tsx +++ b/packages/@headlessui-react/src/components/radio-group/radio-group.tsx @@ -61,7 +61,7 @@ let reducers: { }, [ActionTypes.UnregisterOption](state, action) { let options = state.options.slice() - let idx = state.options.findIndex(radio => radio.id === action.id) + let idx = state.options.findIndex((radio) => radio.id === action.id) if (idx === -1) return state options.splice(idx, 1) return { ...state, options } @@ -123,23 +123,23 @@ export function RadioGroup< let firstOption = useMemo( () => - options.find(option => { + options.find((option) => { if (option.propsRef.current.disabled) return false return true }), [options] ) let containsCheckedOption = useMemo( - () => options.some(option => option.propsRef.current.value === value), + () => options.some((option) => option.propsRef.current.value === value), [options, value] ) let triggerChange = useCallback( - nextValue => { + (nextValue) => { if (disabled) return false if (nextValue === value) return false - let nextOption = options.find(option => option.propsRef.current.value === nextValue)?.propsRef - .current + let nextOption = options.find((option) => option.propsRef.current.value === nextValue) + ?.propsRef.current if (nextOption?.disabled) return false onChange(nextValue) @@ -166,8 +166,8 @@ export function RadioGroup< if (!container) return let all = options - .filter(option => option.propsRef.current.disabled === false) - .map(radio => radio.element.current) as HTMLElement[] + .filter((option) => option.propsRef.current.disabled === false) + .map((radio) => radio.element.current) as HTMLElement[] switch (event.key) { case Keys.ArrowLeft: @@ -180,7 +180,7 @@ export function RadioGroup< if (result === FocusResult.Success) { let activeOption = options.find( - option => option.element.current === document.activeElement + (option) => option.element.current === document.activeElement ) if (activeOption) triggerChange(activeOption.propsRef.current.value) } @@ -197,7 +197,7 @@ export function RadioGroup< if (result === FocusResult.Success) { let activeOption = options.find( - option => option.element.current === document.activeElement + (option) => option.element.current === document.activeElement ) if (activeOption) triggerChange(activeOption.propsRef.current.value) } @@ -210,7 +210,7 @@ export function RadioGroup< event.stopPropagation() let activeOption = options.find( - option => option.element.current === document.activeElement + (option) => option.element.current === document.activeElement ) if (activeOption) triggerChange(activeOption.propsRef.current.value) } @@ -322,14 +322,12 @@ function Option< firstOption, containsCheckedOption, value: radioGroupValue, - } = useRadioGroupContext([RadioGroup.name, Option.name].join('.')) + } = useRadioGroupContext('RadioGroup.Option') - useIsoMorphicEffect(() => registerOption({ id, element: optionRef, propsRef }), [ - id, - registerOption, - optionRef, - props, - ]) + useIsoMorphicEffect( + () => registerOption({ id, element: optionRef, propsRef }), + [id, registerOption, optionRef, props] + ) let handleClick = useCallback(() => { if (!change(value)) return diff --git a/packages/@headlessui-react/src/components/switch/switch.test.tsx b/packages/@headlessui-react/src/components/switch/switch.test.tsx index d566a48261..986664b79d 100644 --- a/packages/@headlessui-react/src/components/switch/switch.test.tsx +++ b/packages/@headlessui-react/src/components/switch/switch.test.tsx @@ -214,7 +214,7 @@ describe('Keyboard interactions', () => { return ( { + onChange={(value) => { setState(value) handleChange(value) }} @@ -297,7 +297,7 @@ describe('Mouse interactions', () => { return ( { + onChange={(value) => { setState(value) handleChange(value) }} @@ -331,7 +331,7 @@ describe('Mouse interactions', () => { { + onChange={(value) => { setState(value) handleChange(value) }} @@ -373,7 +373,7 @@ describe('Mouse interactions', () => { { + onChange={(value) => { setState(value) handleChange(value) }} diff --git a/packages/@headlessui-react/src/components/tabs/tabs.test.tsx b/packages/@headlessui-react/src/components/tabs/tabs.test.tsx index b58f138035..d824817405 100644 --- a/packages/@headlessui-react/src/components/tabs/tabs.test.tsx +++ b/packages/@headlessui-react/src/components/tabs/tabs.test.tsx @@ -81,7 +81,7 @@ describe('Rendering', () => { return ( <> - + Tab 1 @@ -118,7 +118,7 @@ describe('Rendering', () => { it('should expose the `selectedIndex` on the `Tab.Group` component', async () => { render( - {data => ( + {(data) => ( <>
{JSON.stringify(data)}
@@ -153,7 +153,7 @@ describe('Rendering', () => { render( - {data => ( + {(data) => ( <>
{JSON.stringify(data)}
Tab 1 @@ -192,7 +192,7 @@ describe('Rendering', () => {
- {data => ( + {(data) => ( <>
{JSON.stringify(data)}
Content 1 @@ -220,7 +220,7 @@ describe('Rendering', () => { - {data => ( + {(data) => ( <>
{JSON.stringify(data)}
Tab 1 @@ -228,7 +228,7 @@ describe('Rendering', () => { )}
- {data => ( + {(data) => ( <>
{JSON.stringify(data)}
Tab 2 @@ -236,7 +236,7 @@ describe('Rendering', () => { )}
- {data => ( + {(data) => ( <>
{JSON.stringify(data)}
Tab 3 @@ -287,7 +287,7 @@ describe('Rendering', () => { - {data => ( + {(data) => ( <>
{JSON.stringify(data)}
Content 1 @@ -295,7 +295,7 @@ describe('Rendering', () => { )}
- {data => ( + {(data) => ( <>
{JSON.stringify(data)}
Content 2 @@ -303,7 +303,7 @@ describe('Rendering', () => { )}
- {data => ( + {(data) => ( <>
{JSON.stringify(data)}
Content 3 @@ -514,7 +514,7 @@ describe('Rendering', () => { <> { + onChange={(value) => { setSelectedIndex(value) handleChange(value) }} @@ -533,7 +533,7 @@ describe('Rendering', () => { - + ) } diff --git a/packages/@headlessui-react/src/components/tabs/tabs.tsx b/packages/@headlessui-react/src/components/tabs/tabs.tsx index 5e057e55d5..4f8c000ecd 100644 --- a/packages/@headlessui-react/src/components/tabs/tabs.tsx +++ b/packages/@headlessui-react/src/components/tabs/tabs.tsx @@ -83,14 +83,14 @@ let reducers: { return { ...state, tabs: [...state.tabs, action.tab] } }, [ActionTypes.UnregisterTab](state, action) { - return { ...state, tabs: state.tabs.filter(tab => tab !== action.tab) } + return { ...state, tabs: state.tabs.filter((tab) => tab !== action.tab) } }, [ActionTypes.RegisterPanel](state, action) { if (state.panels.includes(action.panel)) return state return { ...state, panels: [...state.panels, action.panel] } }, [ActionTypes.UnregisterPanel](state, action) { - return { ...state, panels: state.panels.filter(panel => panel !== action.panel) } + return { ...state, panels: state.panels.filter((panel) => panel !== action.panel) } }, [ActionTypes.ForceRerender](state) { return { ...state } @@ -171,8 +171,8 @@ function Tabs( if (state.tabs.length <= 0) return if (selectedIndex === null && state.selectedIndex !== null) return - let tabs = state.tabs.map(tab => tab.current).filter(Boolean) as HTMLElement[] - let focusableTabs = tabs.filter(tab => !tab.hasAttribute('disabled')) + let tabs = state.tabs.map((tab) => tab.current).filter(Boolean) as HTMLElement[] + let focusableTabs = tabs.filter((tab) => !tab.hasAttribute('disabled')) let indexToSet = selectedIndex ?? defaultIndex @@ -194,7 +194,7 @@ function Tabs( let before = tabs.slice(0, indexToSet) let after = tabs.slice(indexToSet) - let next = [...after, ...before].find(tab => focusableTabs.includes(tab)) + let next = [...after, ...before].find((tab) => focusableTabs.includes(tab)) if (!next) return dispatch({ type: ActionTypes.SetSelectedIndex, index: tabs.indexOf(next) }) @@ -245,7 +245,7 @@ type ListPropsWeControl = 'role' | 'aria-orientation' function List( props: Props & {} ) { - let [{ selectedIndex, orientation }] = useTabsContext([Tab.name, List.name].join('.')) + let [{ selectedIndex, orientation }] = useTabsContext('Tab.List') let slot = { selectedIndex } let propsWeControl = { @@ -275,13 +275,11 @@ export function Tab( ) { let id = `headlessui-tabs-tab-${useId()}` - let [ - { selectedIndex, tabs, panels, orientation, activation }, - { dispatch, change }, - ] = useTabsContext(Tab.name) + let [{ selectedIndex, tabs, panels, orientation, activation }, { dispatch, change }] = + useTabsContext(Tab.name) let internalTabRef = useRef(null) - let tabRef = useSyncRefs(internalTabRef, element => { + let tabRef = useSyncRefs(internalTabRef, (element) => { if (!element) return dispatch({ type: ActionTypes.ForceRerender }) }) @@ -296,7 +294,7 @@ export function Tab( let handleKeyDown = useCallback( (event: ReactKeyboardEvent) => { - let list = tabs.map(tab => tab.current).filter(Boolean) as HTMLElement[] + let list = tabs.map((tab) => tab.current).filter(Boolean) as HTMLElement[] if (event.key === Keys.Space || event.key === Keys.Enter) { event.preventDefault() @@ -380,7 +378,7 @@ interface PanelsRenderPropArg { function Panels( props: Props ) { - let [{ selectedIndex }] = useTabsContext([Tab.name, Panels.name].join('.')) + let [{ selectedIndex }] = useTabsContext('Tab.Panels') let slot = useMemo(() => ({ selectedIndex }), [selectedIndex]) @@ -405,13 +403,11 @@ function Panel( props: Props & PropsForFeatures ) { - let [{ selectedIndex, tabs, panels }, { dispatch }] = useTabsContext( - [Tab.name, Panel.name].join('.') - ) + let [{ selectedIndex, tabs, panels }, { dispatch }] = useTabsContext('Tab.Panel') let id = `headlessui-tabs-panel-${useId()}` let internalPanelRef = useRef(null) - let panelRef = useSyncRefs(internalPanelRef, element => { + let panelRef = useSyncRefs(internalPanelRef, (element) => { if (!element) return dispatch({ type: ActionTypes.ForceRerender }) }) diff --git a/packages/@headlessui-react/src/components/transitions/transition.test.tsx b/packages/@headlessui-react/src/components/transitions/transition.test.tsx index 3a3aeb0f0c..8dfcc004c4 100644 --- a/packages/@headlessui-react/src/components/transitions/transition.test.tsx +++ b/packages/@headlessui-react/src/components/transitions/transition.test.tsx @@ -26,8 +26,6 @@ it( expect(() => { render( - // @ts-expect-error Disabling TS because it does require us to use a show prop. But non - // TypeScript projects won't benefit from this.
Children
@@ -445,7 +443,7 @@ describe('Transitions', () => { Hello! - @@ -488,14 +486,15 @@ describe('Transitions', () => { return ( <> - + Hello! - @@ -538,14 +537,15 @@ describe('Transitions', () => { return ( <> - + Hello! - @@ -591,7 +591,7 @@ describe('Transitions', () => { Hello! - @@ -642,7 +642,7 @@ describe('Transitions', () => { Hello! - @@ -696,7 +696,7 @@ describe('Transitions', () => { Hello! - @@ -757,7 +757,7 @@ describe('Transitions', () => { Hello! - @@ -843,7 +843,7 @@ describe('Transitions', () => { Hello! - @@ -943,7 +943,7 @@ describe('Transitions', () => { - @@ -1027,7 +1027,7 @@ describe('Transitions', () => { - @@ -1138,7 +1138,7 @@ describe('Events', () => { Hello! - diff --git a/packages/@headlessui-react/src/components/transitions/transition.tsx b/packages/@headlessui-react/src/components/transitions/transition.tsx index c3446f3caf..f3f8595273 100644 --- a/packages/@headlessui-react/src/components/transitions/transition.tsx +++ b/packages/@headlessui-react/src/components/transitions/transition.tsx @@ -28,9 +28,10 @@ import { useServerHandoffComplete } from '../../hooks/use-server-handoff-complet type ID = ReturnType function useSplitClasses(classes: string = '') { - return useMemo(() => classes.split(' ').filter(className => className.trim().length > 1), [ - classes, - ]) + return useMemo( + () => classes.split(' ').filter((className) => className.trim().length > 1), + [classes] + ) } interface TransitionContextValues { @@ -287,23 +288,37 @@ function TransitionChild { - isTransitioning.current = false - if (reason === Reason.Finished) events.current.afterEnter() - }) - : transition(node, leaveClasses, leaveFromClasses, leaveToClasses, enteredClasses, reason => { - isTransitioning.current = false - - if (reason !== Reason.Finished) return - - // When we don't have children anymore we can safely unregister from the parent and hide - // ourselves. - if (!hasChildren(nesting)) { - setState(TreeStates.Hidden) - unregister(id) - events.current.afterLeave() + ? transition( + node, + enterClasses, + enterFromClasses, + enterToClasses, + enteredClasses, + (reason) => { + isTransitioning.current = false + if (reason === Reason.Finished) events.current.afterEnter() + } + ) + : transition( + node, + leaveClasses, + leaveFromClasses, + leaveToClasses, + enteredClasses, + (reason) => { + isTransitioning.current = false + + if (reason !== Reason.Finished) return + + // When we don't have children anymore we can safely unregister from the parent and hide + // ourselves. + if (!hasChildren(nesting)) { + setState(TreeStates.Hidden) + unregister(id) + events.current.afterLeave() + } } - }) + ) }, [ events, id, @@ -359,7 +374,7 @@ export function Transition is used but it is missing a `show={true | false}` prop.') } diff --git a/packages/@headlessui-react/src/components/transitions/utils/transition.test.ts b/packages/@headlessui-react/src/components/transitions/utils/transition.test.ts index 9918716179..58cd91a0aa 100644 --- a/packages/@headlessui-react/src/components/transitions/utils/transition.test.ts +++ b/packages/@headlessui-react/src/components/transitions/utils/transition.test.ts @@ -17,7 +17,7 @@ it('should be possible to transition', async () => { d.add( reportChanges( () => document.body.innerHTML, - content => { + (content) => { snapshots.push({ content, recordedAt: process.hrtime.bigint(), @@ -26,11 +26,11 @@ it('should be possible to transition', async () => { ) ) - await new Promise(resolve => { + await new Promise((resolve) => { transition(element, ['enter'], ['enterFrom'], ['enterTo'], ['entered'], resolve) }) - await new Promise(resolve => d.nextFrame(resolve)) + await new Promise((resolve) => d.nextFrame(resolve)) // Initial render: expect(snapshots[0].content).toEqual('
') @@ -61,7 +61,7 @@ it('should wait the correct amount of time to finish a transition', async () => d.add( reportChanges( () => document.body.innerHTML, - content => { + (content) => { snapshots.push({ content, recordedAt: process.hrtime.bigint(), @@ -70,11 +70,11 @@ it('should wait the correct amount of time to finish a transition', async () => ) ) - let reason = await new Promise(resolve => { + let reason = await new Promise((resolve) => { transition(element, ['enter'], ['enterFrom'], ['enterTo'], ['entered'], resolve) }) - await new Promise(resolve => d.nextFrame(resolve)) + await new Promise((resolve) => d.nextFrame(resolve)) expect(reason).toBe(Reason.Finished) // Initial render: @@ -118,7 +118,7 @@ it('should keep the delay time into account', async () => { d.add( reportChanges( () => document.body.innerHTML, - content => { + (content) => { snapshots.push({ content, recordedAt: process.hrtime.bigint(), @@ -127,11 +127,11 @@ it('should keep the delay time into account', async () => { ) ) - let reason = await new Promise(resolve => { + let reason = await new Promise((resolve) => { transition(element, ['enter'], ['enterFrom'], ['enterTo'], ['entered'], resolve) }) - await new Promise(resolve => d.nextFrame(resolve)) + await new Promise((resolve) => d.nextFrame(resolve)) expect(reason).toBe(Reason.Finished) let estimatedDuration = Number( @@ -161,7 +161,7 @@ it('should be possible to cancel a transition at any time', async () => { d.add( reportChanges( () => document.body.innerHTML, - content => { + (content) => { let recordedAt = process.hrtime.bigint() let total = snapshots.length @@ -178,16 +178,16 @@ it('should be possible to cancel a transition at any time', async () => { expect.assertions(2) // Setup the transition - let cancel = transition(element, ['enter'], ['enterFrom'], ['enterTo'], ['entered'], reason => { + let cancel = transition(element, ['enter'], ['enterFrom'], ['enterTo'], ['entered'], (reason) => { expect(reason).toBe(Reason.Cancelled) }) // Wait for a bit - await new Promise(resolve => setTimeout(resolve, 20)) + await new Promise((resolve) => setTimeout(resolve, 20)) // Cancel the transition cancel() - await new Promise(resolve => d.nextFrame(resolve)) + await new Promise((resolve) => d.nextFrame(resolve)) - expect(snapshots.map(snapshot => snapshot.content).join('\n')).not.toContain('enterTo') + expect(snapshots.map((snapshot) => snapshot.content).join('\n')).not.toContain('enterTo') }) diff --git a/packages/@headlessui-react/src/components/transitions/utils/transition.ts b/packages/@headlessui-react/src/components/transitions/utils/transition.ts index 6201eae0cb..01d657c2c7 100644 --- a/packages/@headlessui-react/src/components/transitions/utils/transition.ts +++ b/packages/@headlessui-react/src/components/transitions/utils/transition.ts @@ -22,13 +22,13 @@ function waitForTransition(node: HTMLElement, done: (reason: Reason) => void) { // Safari returns a comma separated list of values, so let's sort them and take the highest value. let { transitionDuration, transitionDelay } = getComputedStyle(node) - let [durationMs, delaysMs] = [transitionDuration, transitionDelay].map(value => { + let [durationMs, delaysMs] = [transitionDuration, transitionDelay].map((value) => { let [resolvedValue = 0] = value .split(',') // Remove falsy we can't work with .filter(Boolean) // Values are returned as `0.3s` or `75ms` - .map(v => (v.includes('ms') ? parseFloat(v) : parseFloat(v) * 1000)) + .map((v) => (v.includes('ms') ? parseFloat(v) : parseFloat(v) * 1000)) .sort((a, z) => z - a) return resolvedValue @@ -74,7 +74,7 @@ export function transition( addClasses(node, ...to) d.add( - waitForTransition(node, reason => { + waitForTransition(node, (reason) => { removeClasses(node, ...to, ...base) addClasses(node, ...entered) return _done(reason) diff --git a/packages/@headlessui-react/src/hooks/use-flags.ts b/packages/@headlessui-react/src/hooks/use-flags.ts index 1cb5448e25..7096093a3d 100644 --- a/packages/@headlessui-react/src/hooks/use-flags.ts +++ b/packages/@headlessui-react/src/hooks/use-flags.ts @@ -3,10 +3,10 @@ import { useState, useCallback } from 'react' export function useFlags(initialFlags = 0) { let [flags, setFlags] = useState(initialFlags) - let addFlag = useCallback((flag: number) => setFlags(flags => flags | flag), [setFlags]) + let addFlag = useCallback((flag: number) => setFlags((flags) => flags | flag), [setFlags]) let hasFlag = useCallback((flag: number) => Boolean(flags & flag), [flags]) - let removeFlag = useCallback((flag: number) => setFlags(flags => flags & ~flag), [setFlags]) - let toggleFlag = useCallback((flag: number) => setFlags(flags => flags ^ flag), [setFlags]) + let removeFlag = useCallback((flag: number) => setFlags((flags) => flags & ~flag), [setFlags]) + let toggleFlag = useCallback((flag: number) => setFlags((flags) => flags ^ flag), [setFlags]) return { addFlag, hasFlag, removeFlag, toggleFlag } } diff --git a/packages/@headlessui-react/src/hooks/use-focus-trap.ts b/packages/@headlessui-react/src/hooks/use-focus-trap.ts index 68b4c282ac..fd99685552 100644 --- a/packages/@headlessui-react/src/hooks/use-focus-trap.ts +++ b/packages/@headlessui-react/src/hooks/use-focus-trap.ts @@ -97,7 +97,7 @@ export function useFocusTrap( }, [container, initialFocus, featuresInitialFocus]) // Handle `Tab` & `Shift+Tab` keyboard events - useWindowEvent('keydown', event => { + useWindowEvent('keydown', (event) => { if (!(features & Features.TabLock)) return if (!container.current) return @@ -118,7 +118,7 @@ export function useFocusTrap( // Prevent programmatically escaping the container useWindowEvent( 'focus', - event => { + (event) => { if (!(features & Features.FocusLock)) return let allContainers = new Set(containers?.current) diff --git a/packages/@headlessui-react/src/hooks/use-inert-others.test.tsx b/packages/@headlessui-react/src/hooks/use-inert-others.test.tsx index 15b6f0274e..f03c3c957a 100644 --- a/packages/@headlessui-react/src/hooks/use-inert-others.test.tsx +++ b/packages/@headlessui-react/src/hooks/use-inert-others.test.tsx @@ -17,7 +17,7 @@ it('should be possible to inert other elements', async () => { return (
- +
) } @@ -61,7 +61,7 @@ it('should restore inert elements, when all useInertOthers calls are disabled', return (
- +
) } @@ -136,7 +136,7 @@ it('should restore inert elements, when all useInertOthers calls are disabled (i return (
- +
) @@ -221,7 +221,7 @@ it('should handle inert others correctly when 2 useInertOthers are used in a sha return (
- +
) } diff --git a/packages/@headlessui-react/src/hooks/use-inert-others.ts b/packages/@headlessui-react/src/hooks/use-inert-others.ts index 49537b83e8..a90f87686b 100644 --- a/packages/@headlessui-react/src/hooks/use-inert-others.ts +++ b/packages/@headlessui-react/src/hooks/use-inert-others.ts @@ -42,7 +42,7 @@ export function useInertOthers( } // Collect direct children of the body - document.querySelectorAll('body > *').forEach(child => { + document.querySelectorAll('body > *').forEach((child) => { if (!(child instanceof HTMLElement)) return // Skip non-HTMLElements // Skip the interactables, and the parents of the interactables @@ -71,7 +71,7 @@ export function useInertOthers( // will become inert as well. if (interactables.size > 0) { // Collect direct children of the body - document.querySelectorAll('body > *').forEach(child => { + document.querySelectorAll('body > *').forEach((child) => { if (!(child instanceof HTMLElement)) return // Skip non-HTMLElements // Skip already inert parents diff --git a/packages/@headlessui-react/src/hooks/use-tree-walker.ts b/packages/@headlessui-react/src/hooks/use-tree-walker.ts index 4dedafb7c1..dfe0123830 100644 --- a/packages/@headlessui-react/src/hooks/use-tree-walker.ts +++ b/packages/@headlessui-react/src/hooks/use-tree-walker.ts @@ -35,6 +35,7 @@ export function useTreeWalker({ let walk = walkRef.current let acceptNode = Object.assign((node: HTMLElement) => accept(node), { acceptNode: accept }) + // @ts-expect-error This `false` is a simple small fix for older browsers let walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, acceptNode, false) while (walker.nextNode()) walk(walker.currentNode as HTMLElement) diff --git a/packages/@headlessui-react/src/test-utils/accessibility-assertions.ts b/packages/@headlessui-react/src/test-utils/accessibility-assertions.ts index f478642b9a..d2ef0479ed 100644 --- a/packages/@headlessui-react/src/test-utils/accessibility-assertions.ts +++ b/packages/@headlessui-react/src/test-utils/accessibility-assertions.ts @@ -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') diff --git a/packages/@headlessui-react/src/test-utils/execute-timeline.ts b/packages/@headlessui-react/src/test-utils/execute-timeline.ts index 8b032c1721..0c308a7321 100644 --- a/packages/@headlessui-react/src/test-utils/execute-timeline.ts +++ b/packages/@headlessui-react/src/test-utils/execute-timeline.ts @@ -17,7 +17,7 @@ function redentSnapshot(input: string) { return input .split('\n') - .map(line => + .map((line) => line.trim() === '---' ? line : line.replace(replacer, (_, sign, rest) => `${sign} ${rest}`) ) .join('\n') @@ -69,13 +69,13 @@ export async function executeTimeline( .reduce((total, current) => total + current, 0) // Changes happen in the next frame - await new Promise(resolve => d.nextFrame(resolve)) + await new Promise((resolve) => d.nextFrame(resolve)) // We wait for the amount of the duration - await new Promise(resolve => d.setTimeout(resolve, totalDuration)) + await new Promise((resolve) => d.setTimeout(resolve, totalDuration)) // We wait an additional next frame so that we know that we are done - await new Promise(resolve => d.nextFrame(resolve)) + await new Promise((resolve) => d.nextFrame(resolve)) }, Promise.resolve()) if (snapshots.length <= 0) { @@ -127,7 +127,7 @@ export async function executeTimeline( .replace(/Snapshot Diff:\n/g, '') ) .split('\n') - .map(line => ` ${line}`) + .map((line) => ` ${line}`) .join('\n')}` }) .filter(Boolean) diff --git a/packages/@headlessui-react/src/test-utils/interactions.test.tsx b/packages/@headlessui-react/src/test-utils/interactions.test.tsx index 0e6925fc66..e4701f1556 100644 --- a/packages/@headlessui-react/src/test-utils/interactions.test.tsx +++ b/packages/@headlessui-react/src/test-utils/interactions.test.tsx @@ -175,7 +175,7 @@ describe('Keyboard', () => { await type([key(input)]) - let expected = result.map(e => event(e)) + let expected = result.map((e) => event(e)) expect(fired.length).toEqual(result.length) diff --git a/packages/@headlessui-react/src/test-utils/interactions.ts b/packages/@headlessui-react/src/test-utils/interactions.ts index b65ece9968..71fef368c7 100644 --- a/packages/@headlessui-react/src/test-utils/interactions.ts +++ b/packages/@headlessui-react/src/test-utils/interactions.ts @@ -36,7 +36,7 @@ export function shift(event: Partial) { } export function word(input: string): Partial[] { - 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[], 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(',') diff --git a/packages/@headlessui-react/src/test-utils/suppress-console-logs.ts b/packages/@headlessui-react/src/test-utils/suppress-console-logs.ts index da8e6d1216..0de4a0b4e3 100644 --- a/packages/@headlessui-react/src/test-utils/suppress-console-logs.ts +++ b/packages/@headlessui-react/src/test-utils/suppress-console-logs.ts @@ -5,10 +5,10 @@ type FunctionPropertyNames = { export function suppressConsoleLogs( cb: (...args: T) => unknown, - type: FunctionPropertyNames = 'error' + type: FunctionPropertyNames = 'error' ) { return (...args: T) => { - let spy = jest.spyOn(global.console, type).mockImplementation(jest.fn()) + let spy = jest.spyOn(globalThis.console, type).mockImplementation(jest.fn()) return new Promise((resolve, reject) => { Promise.resolve(cb(...args)).then(resolve, reject) diff --git a/packages/@headlessui-react/src/utils/calculate-active-index.ts b/packages/@headlessui-react/src/utils/calculate-active-index.ts index cc296a9068..16ed66ffb0 100644 --- a/packages/@headlessui-react/src/utils/calculate-active-index.ts +++ b/packages/@headlessui-react/src/utils/calculate-active-index.ts @@ -40,7 +40,7 @@ export function calculateActiveIndex( let nextActiveIndex = (() => { switch (action.focus) { case Focus.First: - return items.findIndex(item => !resolvers.resolveDisabled(item)) + return items.findIndex((item) => !resolvers.resolveDisabled(item)) case Focus.Previous: { let idx = items @@ -64,13 +64,13 @@ export function calculateActiveIndex( let idx = items .slice() .reverse() - .findIndex(item => !resolvers.resolveDisabled(item)) + .findIndex((item) => !resolvers.resolveDisabled(item)) if (idx === -1) return idx return items.length - 1 - idx } case Focus.Specific: - return items.findIndex(item => resolvers.resolveId(item) === action.id) + return items.findIndex((item) => resolvers.resolveId(item) === action.id) case Focus.Nothing: return null diff --git a/packages/@headlessui-react/src/utils/focus-management.ts b/packages/@headlessui-react/src/utils/focus-management.ts index f48158b1da..703e87d5c0 100644 --- a/packages/@headlessui-react/src/utils/focus-management.ts +++ b/packages/@headlessui-react/src/utils/focus-management.ts @@ -18,8 +18,8 @@ let focusableSelector = [ ? // TODO: Remove this once JSDOM fixes the issue where an element that is // "hidden" can be the document.activeElement, because this is not possible // in real browsers. - selector => `${selector}:not([tabindex='-1']):not([style*='display: none'])` - : selector => `${selector}:not([tabindex='-1'])` + (selector) => `${selector}:not([tabindex='-1']):not([style*='display: none'])` + : (selector) => `${selector}:not([tabindex='-1'])` ) .join(',') diff --git a/packages/@headlessui-react/src/utils/match.ts b/packages/@headlessui-react/src/utils/match.ts index 80496d12a2..c4becd32cd 100644 --- a/packages/@headlessui-react/src/utils/match.ts +++ b/packages/@headlessui-react/src/utils/match.ts @@ -12,7 +12,7 @@ export function match `"${key}"`) + .map((key) => `"${key}"`) .join(', ')}.` ) if (Error.captureStackTrace) Error.captureStackTrace(error, match) diff --git a/packages/@headlessui-react/src/utils/render.test.tsx b/packages/@headlessui-react/src/utils/render.test.tsx index cef084a2cd..9c743c4520 100644 --- a/packages/@headlessui-react/src/utils/render.test.tsx +++ b/packages/@headlessui-react/src/utils/render.test.tsx @@ -45,7 +45,7 @@ describe('Default functionality', () => { testRender( - {data => { + {(data) => { expect(data).toBe(slot) return Contents diff --git a/packages/@headlessui-react/src/utils/render.ts b/packages/@headlessui-react/src/utils/render.ts index 1fe004787b..b353e13923 100644 --- a/packages/@headlessui-react/src/utils/render.ts +++ b/packages/@headlessui-react/src/utils/render.ts @@ -102,10 +102,12 @@ function _render( tag: ElementType, name: string ) { - let { as: Component = tag, children, refName = 'ref', ...passThroughProps } = omit(props, [ - 'unmount', - 'static', - ]) + let { + as: Component = tag, + children, + refName = 'ref', + ...passThroughProps + } = omit(props, ['unmount', 'static']) // This allows us to use `` let refRelatedProps = props.ref !== undefined ? { [refName]: props.ref } : {} @@ -132,7 +134,7 @@ function _render( `The current component <${name} /> is rendering a "Fragment".`, `However we need to passthrough the following props:`, Object.keys(passThroughProps) - .map(line => ` - ${line}`) + .map((line) => ` - ${line}`) .join('\n'), '', 'You can apply a few solutions:', @@ -140,7 +142,7 @@ function _render( 'Add an `as="..."` prop, to ensure that we render an actual element instead of a "Fragment".', 'Render a single element as the child so that we can forward the props onto that element.', ] - .map(line => ` - ${line}`) + .map((line) => ` - ${line}`) .join('\n'), ].join('\n') ) @@ -211,7 +213,7 @@ function mergeEventFunctions( export function forwardRefWithAs( component: T ): T & { displayName: string } { - return Object.assign(forwardRef((component as unknown) as any) as any, { + return Object.assign(forwardRef(component as unknown as any) as any, { displayName: component.displayName ?? component.name, }) } diff --git a/packages/@headlessui-react/tsconfig.json b/packages/@headlessui-react/tsconfig.json index cac92c1223..5fb92fde38 100644 --- a/packages/@headlessui-react/tsconfig.json +++ b/packages/@headlessui-react/tsconfig.json @@ -21,13 +21,12 @@ }, "jsx": "preserve", "esModuleInterop": true, - "target": "es5", + "target": "ESNext", "allowJs": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, - "noEmit": true, "resolveJsonModule": true, "isolatedModules": true }, - "exclude": ["node_modules"] + "exclude": ["node_modules", "**/*.test.tsx?"] } diff --git a/packages/@headlessui-react/tsconfig.tsdx.json b/packages/@headlessui-react/tsconfig.tsdx.json deleted file mode 100644 index 1f5d11b1cc..0000000000 --- a/packages/@headlessui-react/tsconfig.tsdx.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "./tsconfig.json", - - "compilerOptions": { - "jsx": "react" - } -} diff --git a/packages/@headlessui-react/tsdx.config.js b/packages/@headlessui-react/tsdx.config.js deleted file mode 100644 index 7ee7a38af3..0000000000 --- a/packages/@headlessui-react/tsdx.config.js +++ /dev/null @@ -1,10 +0,0 @@ -module.exports = { - rollup(config, opts) { - if (opts.format === 'esm') { - config = { ...config, preserveModules: true } - config.output = { ...config.output, dir: 'dist/', entryFileNames: '[name].esm.js' } - delete config.output.file - } - return config - }, -} diff --git a/packages/@headlessui-react/types/jest.d.ts b/packages/@headlessui-react/types/jest.d.ts new file mode 100644 index 0000000000..61902a8f06 --- /dev/null +++ b/packages/@headlessui-react/types/jest.d.ts @@ -0,0 +1,9 @@ +export {} + +declare global { + namespace jest { + interface Matchers { + toBeWithinRenderFrame(actual: number): R + } + } +} diff --git a/packages/@headlessui-vue/.eslintrc.js b/packages/@headlessui-vue/.eslintrc.js deleted file mode 100644 index 48cefd8c41..0000000000 --- a/packages/@headlessui-vue/.eslintrc.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - rules: { - 'react-hooks/rules-of-hooks': 'off', - 'react-hooks/exhaustive-deps': 'off', - }, -} diff --git a/packages/@headlessui-vue/build/index.js b/packages/@headlessui-vue/build/index.js new file mode 100644 index 0000000000..473f46702e --- /dev/null +++ b/packages/@headlessui-vue/build/index.js @@ -0,0 +1,7 @@ +'use strict' + +if (process.env.NODE_ENV === 'production') { + module.exports = require('./headlessui.prod.cjs.js') +} else { + module.exports = require('./headlessui.dev.cjs.js') +} diff --git a/packages/@headlessui-vue/package.json b/packages/@headlessui-vue/package.json index 2f99f390d7..f6c49d682d 100644 --- a/packages/@headlessui-vue/package.json +++ b/packages/@headlessui-vue/package.json @@ -4,12 +4,21 @@ "description": "A set of completely unstyled, fully accessible UI components for Vue 3, designed to integrate beautifully with Tailwind CSS.", "main": "dist/index.js", "typings": "dist/index.d.ts", - "module": "dist/index.esm.js", + "module": "dist/headlessui.esm.js", "license": "MIT", "files": [ "README.md", "dist" ], + "exports": { + ".": { + "import": { + "default": "./dist/headlessui.esm.js" + }, + "require": "./dist/index.js", + "types": "./dist/index.d.ts" + } + }, "sideEffects": false, "engines": { "node": ">=10" @@ -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" } } diff --git a/packages/@headlessui-vue/postcss.config.js b/packages/@headlessui-vue/postcss.config.js deleted file mode 100644 index 8db70a9528..0000000000 --- a/packages/@headlessui-vue/postcss.config.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('../../postcss.config.js') diff --git a/packages/@headlessui-vue/src/components/combobox/combobox.test.tsx b/packages/@headlessui-vue/src/components/combobox/combobox.test.tsx index fbe2047a64..7e67c93c84 100644 --- a/packages/@headlessui-vue/src/components/combobox/combobox.test.tsx +++ b/packages/@headlessui-vue/src/components/combobox/combobox.test.tsx @@ -66,7 +66,7 @@ beforeAll(() => { afterAll(() => jest.restoreAllMocks()) function nextFrame() { - return new Promise(resolve => { + return new Promise((resolve) => { requestAnimationFrame(() => { requestAnimationFrame(() => { resolve() @@ -95,9 +95,9 @@ function renderTemplate(input: string | Partial) { return render( defineComponent( - (Object.assign({}, input, { + Object.assign({}, input, { components: { ...defaultComponents, ...input.components }, - }) as unknown) as DefineComponent + }) as Parameters[0] ) ) } @@ -491,9 +491,7 @@ describe('Rendering', () => { template: html` - - Trigger - + Trigger `, 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` - - Trigger - + Trigger `, setup: () => ({ @@ -535,9 +531,7 @@ describe('Rendering', () => { template: html` - - Trigger - + Trigger `, 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` - - Trigger - + Trigger `, setup: () => ({ @@ -765,15 +757,9 @@ describe('Rendering composition', () => { Trigger - - Option A - - - Option B - - - Option C - + Option A + Option B + Option C `, @@ -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', () => { Trigger - - {{JSON.stringify(data)}} - + {{JSON.stringify(data)}} `, @@ -854,9 +838,7 @@ describe('Composition', () => { Trigger - - {{JSON.stringify(data)}} - + {{JSON.stringify(data)}} `, @@ -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', () => { Trigger - - Option A - - - Option B - - - Option C - + Option A + Option B + Option C `, @@ -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', () => { Trigger Option A - - Option B - - - Option C - + Option B + Option C `, @@ -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', () => { Trigger Option A - - Option B - - - Option C - + Option B + Option C `, @@ -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', () => { Trigger - - Option A - + Option A Option B Option C @@ -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', () => { Trigger - - Option A - - - Option B - + Option A + Option B Option C @@ -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', () => { Trigger - - Option A - + Option A Option B Option C @@ -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', () => { Trigger - - Option A - - - Option B - + Option A + Option B Option C @@ -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', () => { Trigger Option A - - Option B - - - Option C - + Option B + Option C `, @@ -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', () => { Trigger - - Option A - - - Option B - + Option A + Option B Option C @@ -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', () => { Trigger Option A - - Option B - - - Option C - + Option B + Option C `, @@ -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', () => { Option A Option B - - Option C - - - Option D - + Option C + Option D `, @@ -3683,15 +3623,9 @@ describe('Keyboard interactions', () => { Trigger Option A - - Option B - - - Option C - - - Option D - + Option B + Option C + Option D `, @@ -3721,18 +3655,10 @@ describe('Keyboard interactions', () => { Trigger - - Option A - - - Option B - - - Option C - - - Option D - + Option A + Option B + Option C + Option D `, @@ -3797,12 +3723,8 @@ describe('Keyboard interactions', () => { Option A Option B - - Option C - - - Option D - + Option C + Option D `, @@ -3836,15 +3758,9 @@ describe('Keyboard interactions', () => { Trigger Option A - - Option B - - - Option C - - - Option D - + Option B + Option C + Option D `, @@ -3874,18 +3790,10 @@ describe('Keyboard interactions', () => { Trigger - - Option A - - - Option B - - - Option C - - - Option D - + Option A + Option B + Option C + Option D `, @@ -3951,12 +3859,8 @@ describe('Keyboard interactions', () => { Trigger - - Option A - - - Option B - + Option A + Option B Option C Option D @@ -3990,15 +3894,9 @@ describe('Keyboard interactions', () => { Trigger - - Option A - - - Option B - - - Option C - + Option A + Option B + Option C Option D @@ -4029,18 +3927,10 @@ describe('Keyboard interactions', () => { Trigger - - Option A - - - Option B - - - Option C - - - Option D - + Option A + Option B + Option C + Option D `, @@ -4106,12 +3996,8 @@ describe('Keyboard interactions', () => { Trigger - - Option A - - - Option B - + Option A + Option B Option C Option D @@ -4145,15 +4031,9 @@ describe('Keyboard interactions', () => { Trigger - - Option A - - - Option B - - - Option C - + Option A + Option B + Option C Option D @@ -4184,18 +4064,10 @@ describe('Keyboard interactions', () => { Trigger - - Option A - - - Option B - - - Option C - - - Option D - + Option A + Option B + Option C + Option D `, @@ -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', () => { Trigger alice - - bob - + bob charlie @@ -5066,9 +4936,7 @@ describe('Mouse interactions', () => { Trigger alice - - bob - + bob charlie @@ -5145,9 +5013,7 @@ describe('Mouse interactions', () => { Trigger alice - - bob - + bob charlie @@ -5227,9 +5093,7 @@ describe('Mouse interactions', () => { Trigger alice - - bob - + bob charlie @@ -5309,9 +5173,7 @@ describe('Mouse interactions', () => { Trigger alice - - bob - + bob charlie diff --git a/packages/@headlessui-vue/src/components/combobox/combobox.ts b/packages/@headlessui-vue/src/components/combobox/combobox.ts index 784ee1cb43..4bb3d67496 100644 --- a/packages/@headlessui-vue/src/components/combobox/combobox.ts +++ b/packages/@headlessui-vue/src/components/combobox/combobox.ts @@ -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 diff --git a/packages/@headlessui-vue/src/components/description/description.test.ts b/packages/@headlessui-vue/src/components/description/description.test.ts index 2a5ba68640..65e6722d0c 100644 --- a/packages/@headlessui-vue/src/components/description/description.test.ts +++ b/packages/@headlessui-vue/src/components/description/description.test.ts @@ -8,7 +8,8 @@ import { html } from '../../test-utils/html' import { click } from '../../test-utils/interactions' import { getByText } from '../../test-utils/accessibility-assertions' -function format(input: Element | string) { +function format(input: Element | null | string) { + if (input === null) throw new Error('input is null') let contents = (typeof input === 'string' ? input : (input as HTMLElement).outerHTML).trim() return prettier.format(contents, { parser: 'babel' }) } @@ -22,59 +23,47 @@ beforeAll(() => { afterAll(() => jest.restoreAllMocks()) -function renderTemplate(input: string | Partial[0]>) { - let defaultComponents = { Description } - - if (typeof input === 'string') { - return render(defineComponent({ template: input, components: defaultComponents })) - } - - return render( - defineComponent( - Object.assign({}, input, { - components: { ...defaultComponents, ...input.components }, - }) as Parameters[0] - ) - ) -} - it('should be possible to use useDescriptions without using a Description', async () => { - let { container } = renderTemplate({ - render() { - return h('div', [h('div', { 'aria-describedby': this.describedby }, ['No description'])]) - }, - setup() { - let describedby = useDescriptions() - return { describedby } - }, - }) + let { container } = render( + defineComponent({ + components: { Description }, + 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`
-
- No description -
+
No description
`) ) }) it('should be possible to use useDescriptions and a single Description, and have them linked', async () => { - let { container } = renderTemplate({ - render() { - return h('div', [ - h('div', { 'aria-describedby': this.describedby }, [ - h(Description, () => 'I am a description'), - h('span', 'Contents'), - ]), - ]) - }, - setup() { - let describedby = useDescriptions() - return { describedby } - }, - }) + let { container } = render( + defineComponent({ + components: { Description }, + 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(nextTick) @@ -82,12 +71,8 @@ it('should be possible to use useDescriptions and a single Description, and have format(html`
-

- I am a description -

- - Contents - +

I am a description

+ Contents
`) @@ -95,21 +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(nextTick) @@ -117,15 +105,9 @@ it('should be possible to use useDescriptions and multiple Description component format(html`
-

- I am a description -

- - Contents - -

- I am also a description -

+

I am a description

+ Contents +

I am also a description

`) @@ -133,21 +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(nextTick) @@ -155,9 +140,7 @@ it('should be possible to update a prop from the parent and it should reflect in format(html`
-

- I am a description -

+

I am a description

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

- I am a description -

+

I am a description

diff --git a/packages/@headlessui-vue/src/components/dialog/dialog.test.ts b/packages/@headlessui-vue/src/components/dialog/dialog.test.ts index 206c4328cf..94e8b83e81 100644 --- a/packages/@headlessui-vue/src/components/dialog/dialog.test.ts +++ b/packages/@headlessui-vue/src/components/dialog/dialog.test.ts @@ -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` -
- `, + template: html`
`, }) jest.mock('../../hooks/use-id') @@ -44,7 +42,7 @@ beforeAll(() => { afterAll(() => jest.restoreAllMocks()) -function renderTemplate(input: string | Partial[0]>) { +function renderTemplate(input: string | ComponentOptionsWithoutProps) { let defaultComponents = { Dialog, DialogOverlay, DialogTitle, DialogDescription, TabSentinel } if (typeof input === 'string') { diff --git a/packages/@headlessui-vue/src/components/dialog/dialog.ts b/packages/@headlessui-vue/src/components/dialog/dialog.ts index 31d7e8808b..5fe71c986d 100644 --- a/packages/@headlessui-vue/src/components/dialog/dialog.ts +++ b/packages/@headlessui-vue/src/components/dialog/dialog.ts @@ -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 && diff --git a/packages/@headlessui-vue/src/components/disclosure/disclosure.test.ts b/packages/@headlessui-vue/src/components/disclosure/disclosure.test.ts index 415513357b..36cb854405 100644 --- a/packages/@headlessui-vue/src/components/disclosure/disclosure.test.ts +++ b/packages/@headlessui-vue/src/components/disclosure/disclosure.test.ts @@ -1,4 +1,4 @@ -import { defineComponent, nextTick, ref, watch, h } from 'vue' +import { defineComponent, nextTick, ref, watch, h, ComponentOptionsWithoutProps } from 'vue' import { render } from '../../test-utils/vue-testing-library' import { Disclosure, DisclosureButton, DisclosurePanel } from './disclosure' import { suppressConsoleLogs } from '../../test-utils/suppress-console-logs' @@ -19,7 +19,7 @@ jest.mock('../../hooks/use-id') afterAll(() => jest.restoreAllMocks()) -function renderTemplate(input: string | Partial[0]>) { +function renderTemplate(input: string | ComponentOptionsWithoutProps) { let defaultComponents = { Disclosure, DisclosureButton, DisclosurePanel } if (typeof input === 'string') { @@ -297,9 +297,7 @@ describe('Rendering', () => { renderTemplate( html` - - Trigger - + Trigger ` ) @@ -311,9 +309,7 @@ describe('Rendering', () => { renderTemplate( html` - - Trigger - + Trigger ` ) @@ -327,14 +323,12 @@ describe('Rendering', () => { renderTemplate({ template: html` - - Trigger - + Trigger `, setup: () => ({ CustomButton: defineComponent({ - setup: props => () => h('button', { ...props }), + setup: (props) => () => h('button', { ...props }), }), }), }) @@ -349,9 +343,7 @@ describe('Rendering', () => { renderTemplate( html` - - Trigger - + Trigger ` ) @@ -365,14 +357,12 @@ describe('Rendering', () => { renderTemplate({ template: html` - - Trigger - + Trigger `, setup: () => ({ CustomButton: defineComponent({ - setup: props => () => h('div', props), + setup: (props) => () => h('div', props), }), }), }) diff --git a/packages/@headlessui-vue/src/components/focus-trap/focus-trap.test.ts b/packages/@headlessui-vue/src/components/focus-trap/focus-trap.test.ts index 8243a82ff4..8d6707250f 100644 --- a/packages/@headlessui-vue/src/components/focus-trap/focus-trap.test.ts +++ b/packages/@headlessui-vue/src/components/focus-trap/focus-trap.test.ts @@ -1,4 +1,4 @@ -import { defineComponent, ref, nextTick, onMounted } from 'vue' +import { defineComponent, ref, nextTick, onMounted, ComponentOptionsWithoutProps } from 'vue' import { FocusTrap } from './focus-trap' import { assertActiveElement, getByText } from '../../test-utils/accessibility-assertions' @@ -16,7 +16,7 @@ beforeAll(() => { afterAll(() => jest.restoreAllMocks()) -function renderTemplate(input: string | Partial[0]>) { +function renderTemplate(input: string | ComponentOptionsWithoutProps) { let defaultComponents = { FocusTrap } if (typeof input === 'string') { @@ -41,7 +41,7 @@ it('should focus the first focusable element inside the FocusTrap', async () => ` ) - await new Promise(nextTick) + await new Promise(nextTick) assertActiveElement(getByText('Trigger')) }) @@ -64,7 +64,7 @@ it('should focus the autoFocus element inside the FocusTrap if that exists', asy }, }) - await new Promise(nextTick) + await new Promise(nextTick) assertActiveElement(document.getElementById('b')) }) @@ -84,7 +84,7 @@ it('should focus the initialFocus element inside the FocusTrap if that exists', }, }) - await new Promise(nextTick) + await new Promise(nextTick) assertActiveElement(document.getElementById('c')) }) @@ -104,7 +104,7 @@ it('should focus the initialFocus element inside the FocusTrap even if another e }, }) - await new Promise(nextTick) + await new Promise(nextTick) assertActiveElement(document.getElementById('c')) }) @@ -121,7 +121,7 @@ it('should warn when there is no focusable element inside the FocusTrap', async ` ) - await new Promise(nextTick) + await new Promise(nextTick) expect(spy.mock.calls[0][0]).toBe('There are no focusable elements inside the ') }) @@ -143,7 +143,7 @@ it( `, }) - await new Promise(nextTick) + await new Promise(nextTick) let [a, b, c, d] = Array.from(document.querySelectorAll('input')) @@ -193,14 +193,10 @@ it('should restore the previously focused element, before entering the FocusTrap template: html`
- + - +
`, @@ -214,7 +210,7 @@ it('should restore the previously focused element, before entering the FocusTrap }, }) - await new Promise(nextTick) + await new Promise(nextTick) // The input should have focus by default because of the autoFocus prop assertActiveElement(document.getElementById('item-1')) @@ -247,7 +243,7 @@ it('should be possible to tab to the next focusable element within the focus tra ` ) - await new Promise(nextTick) + await new Promise(nextTick) // Item A should be focused because the FocusTrap will focus the first item assertActiveElement(document.getElementById('item-a')) @@ -302,12 +298,8 @@ it('should skip the initial "hidden" elements within the focus trap', async () =
- - + + @@ -328,9 +320,7 @@ it('should be possible skip "hidden" elements within the focus trap', async () = - + @@ -364,9 +354,7 @@ it('should be possible skip disabled elements within the focus trap', async () = - + diff --git a/packages/@headlessui-vue/src/components/label/label.test.ts b/packages/@headlessui-vue/src/components/label/label.test.ts index f2184e9b66..67a4113ea3 100644 --- a/packages/@headlessui-vue/src/components/label/label.test.ts +++ b/packages/@headlessui-vue/src/components/label/label.test.ts @@ -8,7 +8,8 @@ import { html } from '../../test-utils/html' import { click } from '../../test-utils/interactions' import { getByText } from '../../test-utils/accessibility-assertions' -function format(input: Element | string) { +function format(input: Element | null | string) { + if (input === null) throw new Error('input is null') let contents = (typeof input === 'string' ? input : (input as HTMLElement).outerHTML).trim() return prettier.format(contents, { parser: 'babel' }) } @@ -22,59 +23,47 @@ beforeAll(() => { afterAll(() => jest.restoreAllMocks()) -function renderTemplate(input: string | Partial[0]>) { - let defaultComponents = { Label } - - if (typeof input === 'string') { - return render(defineComponent({ template: input, components: defaultComponents })) - } - - return render( - defineComponent( - Object.assign({}, input, { - components: { ...defaultComponents, ...input.components }, - }) as Parameters[0] - ) - ) -} - it('should be possible to use useLabels without using a Label', async () => { - let { container } = renderTemplate({ - render() { - return h('div', [h('div', { 'aria-labelledby': this.labelledby }, ['No label'])]) - }, - setup() { - let labelledby = useLabels() - return { labelledby } - }, - }) + let { container } = render( + defineComponent({ + components: { Label }, + 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`
-
- No label -
+
No label
`) ) }) it('should be possible to use useLabels and a single Label, and have them linked', async () => { - let { container } = renderTemplate({ - render() { - return h('div', [ - h('div', { 'aria-labelledby': this.labelledby }, [ - h(Label, () => 'I am a label'), - h('span', 'Contents'), - ]), - ]) - }, - setup() { - let labelledby = useLabels() - return { labelledby } - }, - }) + let { container } = render( + defineComponent({ + components: { Label }, + 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(nextTick) @@ -82,12 +71,8 @@ it('should be possible to use useLabels and a single Label, and have them linked format(html`
- - - Contents - + + Contents
`) @@ -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(nextTick) @@ -117,15 +105,9 @@ it('should be possible to use useLabels and multiple Label components, and have format(html`
- - - Contents - - + + Contents +
`) @@ -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(nextTick) @@ -155,9 +140,7 @@ it('should be possible to update a prop from the parent and it should reflect in format(html`
- +
@@ -170,9 +153,7 @@ it('should be possible to update a prop from the parent and it should reflect in format(html`
- +
diff --git a/packages/@headlessui-vue/src/components/listbox/listbox.test.tsx b/packages/@headlessui-vue/src/components/listbox/listbox.test.tsx index c0a437e995..c3cd561fef 100644 --- a/packages/@headlessui-vue/src/components/listbox/listbox.test.tsx +++ b/packages/@headlessui-vue/src/components/listbox/listbox.test.tsx @@ -1,4 +1,12 @@ -import { defineComponent, nextTick, ref, watch, h, reactive } from 'vue' +import { + defineComponent, + nextTick, + ref, + watch, + h, + reactive, + ComponentOptionsWithoutProps, +} from 'vue' import { render } from '../../test-utils/vue-testing-library' import { Listbox, ListboxLabel, ListboxButton, ListboxOptions, ListboxOption } from './listbox' import { suppressConsoleLogs } from '../../test-utils/suppress-console-logs' @@ -48,7 +56,7 @@ beforeAll(() => { afterAll(() => jest.restoreAllMocks()) function nextFrame() { - return new Promise(resolve => { + return new Promise((resolve) => { requestAnimationFrame(() => { requestAnimationFrame(() => { resolve() @@ -57,7 +65,7 @@ function nextFrame() { }) } -function renderTemplate(input: string | Partial[0]>) { +function renderTemplate(input: string | ComponentOptionsWithoutProps) { let defaultComponents = { Listbox, ListboxLabel, ListboxButton, ListboxOptions, ListboxOption } if (typeof input === 'string') { @@ -388,9 +396,7 @@ describe('Rendering', () => { renderTemplate({ template: html` - - Trigger - + Trigger `, setup: () => ({ value: ref(null) }), @@ -405,15 +411,13 @@ describe('Rendering', () => { renderTemplate({ template: html` - - Trigger - + Trigger `, setup: () => ({ value: ref(null), CustomButton: defineComponent({ - setup: props => () => h('button', { ...props }), + setup: (props) => () => h('button', { ...props }), }), }), }) @@ -428,9 +432,7 @@ describe('Rendering', () => { renderTemplate({ template: html` - - Trigger - + Trigger `, setup: () => ({ value: ref(null) }), @@ -445,15 +447,13 @@ describe('Rendering', () => { renderTemplate({ template: html` - - Trigger - + Trigger `, setup: () => ({ value: ref(null), CustomButton: defineComponent({ - setup: props => () => h('div', props), + setup: (props) => () => h('div', props), }), }), }) @@ -647,15 +647,9 @@ describe('Rendering composition', () => { Trigger - - Option A - - - Option B - - - Option C - + Option A + Option B + Option C `, @@ -672,7 +666,7 @@ describe('Rendering composition', () => { await click(getListboxButton()) // Verify options are buttons now - getListboxOptions().forEach(option => assertListboxOption(option, { tag: 'button' })) + getListboxOptions().forEach((option) => assertListboxOption(option, { tag: 'button' })) }) ) }) @@ -704,9 +698,7 @@ describe('Composition', () => { Trigger - - {{JSON.stringify(data)}} - + {{JSON.stringify(data)}} `, @@ -734,9 +726,7 @@ describe('Composition', () => { Trigger - - {{JSON.stringify(data)}} - + {{JSON.stringify(data)}} `, @@ -840,7 +830,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option, { selected: false })) + options.forEach((option) => assertListboxOption(option, { selected: false })) // Verify that the first listbox option is active assertActiveListboxOption(options[0]) @@ -1092,9 +1082,7 @@ describe('Keyboard interactions', () => { Trigger - - Option A - + Option A Option B Option C @@ -1130,12 +1118,8 @@ describe('Keyboard interactions', () => { Trigger - - Option A - - - Option B - + Option A + Option B Option C @@ -1170,15 +1154,9 @@ describe('Keyboard interactions', () => { Trigger - - Option A - - - Option B - - - Option C - + Option A + Option B + Option C `, @@ -1345,7 +1323,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[0]) }) ) @@ -1471,9 +1449,7 @@ describe('Keyboard interactions', () => { Trigger - - Option A - + Option A Option B Option C @@ -1509,12 +1485,8 @@ describe('Keyboard interactions', () => { Trigger - - Option A - - - Option B - + Option A + Option B Option C @@ -1549,15 +1521,9 @@ describe('Keyboard interactions', () => { Trigger - - Option A - - - Option B - - - Option C - + Option A + Option B + Option C `, @@ -1729,7 +1695,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[0]) // Try to tab @@ -1783,7 +1749,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[0]) // Try to Shift+Tab @@ -1839,7 +1805,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) // Verify that the first listbox option is active assertActiveListboxOption(options[0]) @@ -1991,7 +1957,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[0]) // We should be able to go down once @@ -2016,9 +1982,7 @@ describe('Keyboard interactions', () => { Trigger - - Option A - + Option A Option B Option C @@ -2042,7 +2006,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[1]) // We should be able to go down once @@ -2059,12 +2023,8 @@ describe('Keyboard interactions', () => { Trigger - - Option A - - - Option B - + Option A + Option B Option C @@ -2087,7 +2047,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[2]) }) ) @@ -2126,7 +2086,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[0]) // We should be able to go right once @@ -2186,7 +2146,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) // ! ALERT: The LAST option should now be active assertActiveListboxOption(options[2]) @@ -2315,12 +2275,8 @@ describe('Keyboard interactions', () => { Trigger Option A - - Option B - - - Option C - + Option B + Option C `, @@ -2342,7 +2298,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[0]) }) ) @@ -2355,12 +2311,8 @@ describe('Keyboard interactions', () => { Trigger - - Option A - - - Option B - + Option A + Option B Option C @@ -2383,7 +2335,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[2]) // We should not be able to go up (because those are disabled) @@ -2437,7 +2389,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[2]) // We should be able to go down once @@ -2498,7 +2450,7 @@ describe('Keyboard interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) assertActiveListboxOption(options[2]) // We should be able to go left once @@ -2561,12 +2513,8 @@ describe('Keyboard interactions', () => { Option A Option B - - Option C - - - Option D - + Option C + Option D `, @@ -2599,15 +2547,9 @@ describe('Keyboard interactions', () => { Trigger Option A - - Option B - - - Option C - - - Option D - + Option B + Option C + Option D `, @@ -2636,18 +2578,10 @@ describe('Keyboard interactions', () => { Trigger - - Option A - - - Option B - - - Option C - - - Option D - + Option A + Option B + Option C + Option D `, @@ -2713,12 +2647,8 @@ describe('Keyboard interactions', () => { Option A Option B - - Option C - - - Option D - + Option C + Option D `, @@ -2751,15 +2681,9 @@ describe('Keyboard interactions', () => { Trigger Option A - - Option B - - - Option C - - - Option D - + Option B + Option C + Option D `, @@ -2788,18 +2712,10 @@ describe('Keyboard interactions', () => { Trigger - - Option A - - - Option B - - - Option C - - - Option D - + Option A + Option B + Option C + Option D `, @@ -2863,12 +2779,8 @@ describe('Keyboard interactions', () => { Trigger - - Option A - - - Option B - + Option A + Option B Option C Option D @@ -2901,15 +2813,9 @@ describe('Keyboard interactions', () => { Trigger - - Option A - - - Option B - - - Option C - + Option A + Option B + Option C Option D @@ -2939,18 +2845,10 @@ describe('Keyboard interactions', () => { Trigger - - Option A - - - Option B - - - Option C - - - Option D - + Option A + Option B + Option C + Option D `, @@ -3014,12 +2912,8 @@ describe('Keyboard interactions', () => { Trigger - - Option A - - - Option B - + Option A + Option B Option C Option D @@ -3052,15 +2946,9 @@ describe('Keyboard interactions', () => { Trigger - - Option A - - - Option B - - - Option C - + Option A + Option B + Option C Option D @@ -3090,18 +2978,10 @@ describe('Keyboard interactions', () => { Trigger - - Option A - - - Option B - - - Option C - - - Option D - + Option A + Option B + Option C + Option D `, @@ -3252,9 +3132,7 @@ describe('Keyboard interactions', () => { Trigger alice - - bob - + bob charlie @@ -3453,7 +3331,7 @@ describe('Mouse interactions', () => { // Verify we have listbox options let options = getListboxOptions() expect(options).toHaveLength(3) - options.forEach(option => assertListboxOption(option)) + options.forEach((option) => assertListboxOption(option)) }) ) @@ -3845,9 +3723,7 @@ describe('Mouse interactions', () => { Trigger alice - - bob - + bob charlie @@ -3874,9 +3750,7 @@ describe('Mouse interactions', () => { Trigger alice - - bob - + bob charlie @@ -3951,9 +3825,7 @@ describe('Mouse interactions', () => { Trigger alice - - bob - + bob charlie @@ -4031,9 +3903,7 @@ describe('Mouse interactions', () => { Trigger alice - - bob - + bob charlie @@ -4111,9 +3981,7 @@ describe('Mouse interactions', () => { Trigger alice - - bob - + bob charlie diff --git a/packages/@headlessui-vue/src/components/listbox/listbox.ts b/packages/@headlessui-vue/src/components/listbox/listbox.ts index cbc244d0de..680a2f477d 100644 --- a/packages/@headlessui-vue/src/components/listbox/listbox.ts +++ b/packages/@headlessui-vue/src/components/listbox/listbox.ts @@ -130,8 +130,8 @@ export let Listbox = defineComponent({ { resolveItems: () => options.value, resolveActiveIndex: () => activeOptionIndex.value, - resolveId: option => option.id, - resolveDisabled: option => option.dataRef.disabled, + resolveId: (option) => option.id, + resolveDisabled: (option) => option.dataRef.disabled, } ) @@ -153,7 +153,7 @@ export let Listbox = defineComponent({ : options.value let matchingOption = reOrderedOptions.find( - option => + (option) => option.dataRef.textValue.startsWith(searchQuery.value) && !option.dataRef.disabled ) @@ -186,7 +186,7 @@ export let Listbox = defineComponent({ let nextOptions = options.value.slice() let currentActiveOption = activeOptionIndex.value !== null ? nextOptions[activeOptionIndex.value] : null - let idx = nextOptions.findIndex(a => a.id === id) + let idx = nextOptions.findIndex((a) => a.id === id) if (idx !== -1) nextOptions.splice(idx, 1) options.value = nextOptions activeOptionIndex.value = (() => { @@ -204,7 +204,7 @@ export let Listbox = defineComponent({ }, } - useWindowEvent('mousedown', event => { + useWindowEvent('mousedown', (event) => { let target = event.target as HTMLElement let active = document.activeElement @@ -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 }) diff --git a/packages/@headlessui-vue/src/components/menu/menu.test.tsx b/packages/@headlessui-vue/src/components/menu/menu.test.tsx index fe34508d35..4d033b457d 100644 --- a/packages/@headlessui-vue/src/components/menu/menu.test.tsx +++ b/packages/@headlessui-vue/src/components/menu/menu.test.tsx @@ -1,4 +1,12 @@ -import { defineComponent, h, nextTick, reactive, ref, watch } from 'vue' +import { + ComponentOptionsWithoutProps, + defineComponent, + h, + nextTick, + reactive, + ref, + watch, +} from 'vue' import { render } from '../../test-utils/vue-testing-library' import { Menu, MenuButton, MenuItems, MenuItem } from './menu' import { TransitionChild } from '../transitions/transition' @@ -44,7 +52,7 @@ beforeAll(() => { afterAll(() => jest.restoreAllMocks()) function nextFrame() { - return new Promise(resolve => { + return new Promise((resolve) => { requestAnimationFrame(() => { requestAnimationFrame(() => { resolve() @@ -53,7 +61,7 @@ function nextFrame() { }) } -function renderTemplate(input: string | Partial[0]>) { +function renderTemplate(input: string | ComponentOptionsWithoutProps) { let defaultComponents = { Menu, MenuButton, MenuItems, MenuItem } if (typeof input === 'string') { @@ -395,7 +403,7 @@ describe('Rendering', () => { `, setup: () => ({ CustomButton: defineComponent({ - setup: props => () => h('button', { ...props }), + setup: (props) => () => h('button', { ...props }), }), }), }) @@ -433,7 +441,7 @@ describe('Rendering', () => { `, setup: () => ({ CustomButton: defineComponent({ - setup: props => () => h('div', props), + setup: (props) => () => h('div', props), }), }), }) @@ -810,7 +818,7 @@ describe('Rendering composition', () => { // Verify items are buttons now let items = getMenuItems() - items.forEach(item => + items.forEach((item) => assertMenuItem(item, { tag: 'button', attributes: { 'data-my-custom-button': 'true' } }) ) }) @@ -853,11 +861,11 @@ describe('Rendering composition', () => { expect.hasAssertions() - document.querySelectorAll('.outer').forEach(element => { + document.querySelectorAll('.outer').forEach((element) => { expect(element).not.toHaveAttribute('role', 'none') }) - document.querySelectorAll('.inner').forEach(element => { + document.querySelectorAll('.inner').forEach((element) => { expect(element).toHaveAttribute('role', 'none') }) }) @@ -1069,7 +1077,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) // Verify that the first menu item is active assertMenuLinkedWithMenuItem(items[0]) @@ -1398,7 +1406,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) assertMenuLinkedWithMenuItem(items[0]) }) @@ -1704,7 +1712,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) assertMenuLinkedWithMenuItem(items[0]) // Try to tab @@ -1750,7 +1758,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) assertMenuLinkedWithMenuItem(items[0]) // Try to Shift+Tab @@ -1798,7 +1806,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) // Verify that the first menu item is active assertMenuLinkedWithMenuItem(items[0]) @@ -1883,7 +1891,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) assertMenuLinkedWithMenuItem(items[0]) // We should be able to go down once @@ -1926,7 +1934,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) assertMenuLinkedWithMenuItem(items[1]) // We should be able to go down once @@ -1961,7 +1969,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) assertMenuLinkedWithMenuItem(items[2]) }) }) @@ -2002,7 +2010,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) // ! ALERT: The LAST item should now be active assertMenuLinkedWithMenuItem(items[2]) @@ -2055,7 +2063,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) assertMenuLinkedWithMenuItem(items[0]) }) @@ -2086,7 +2094,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) assertMenuLinkedWithMenuItem(items[2]) // We should not be able to go up (because those are disabled) @@ -2133,7 +2141,7 @@ describe('Keyboard interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) assertMenuLinkedWithMenuItem(items[2]) // We should be able to go down once @@ -2820,7 +2828,7 @@ describe('Mouse interactions', () => { // Verify we have menu items let items = getMenuItems() expect(items).toHaveLength(3) - items.forEach(item => assertMenuItem(item)) + items.forEach((item) => assertMenuItem(item)) }) it( diff --git a/packages/@headlessui-vue/src/components/menu/menu.ts b/packages/@headlessui-vue/src/components/menu/menu.ts index 1b25dcbc09..3ffe7bdd33 100644 --- a/packages/@headlessui-vue/src/components/menu/menu.ts +++ b/packages/@headlessui-vue/src/components/menu/menu.ts @@ -96,8 +96,8 @@ export let Menu = defineComponent({ { resolveItems: () => items.value, resolveActiveIndex: () => activeItemIndex.value, - resolveId: item => item.id, - resolveDisabled: item => item.dataRef.disabled, + resolveId: (item) => item.id, + resolveDisabled: (item) => item.dataRef.disabled, } ) @@ -116,7 +116,7 @@ export let Menu = defineComponent({ : items.value let matchingItem = reOrderedItems.find( - item => item.dataRef.textValue.startsWith(searchQuery.value) && !item.dataRef.disabled + (item) => item.dataRef.textValue.startsWith(searchQuery.value) && !item.dataRef.disabled ) let matchIdx = matchingItem ? items.value.indexOf(matchingItem) : -1 @@ -144,7 +144,7 @@ export let Menu = defineComponent({ let nextItems = items.value.slice() let currentActiveItem = activeItemIndex.value !== null ? nextItems[activeItemIndex.value] : null - let idx = nextItems.findIndex(a => a.id === id) + let idx = nextItems.findIndex((a) => a.id === id) if (idx !== -1) nextItems.splice(idx, 1) items.value = nextItems activeItemIndex.value = (() => { @@ -158,7 +158,7 @@ export let Menu = defineComponent({ }, } - useWindowEvent('mousedown', event => { + useWindowEvent('mousedown', (event) => { let target = event.target as HTMLElement let active = document.activeElement @@ -452,10 +452,7 @@ export let MenuItem = defineComponent({ let dataRef = ref({ disabled: props.disabled, textValue: '' }) onMounted(() => { - let textValue = document - .getElementById(id) - ?.textContent?.toLowerCase() - .trim() + let textValue = document.getElementById(id)?.textContent?.toLowerCase().trim() if (textValue !== undefined) dataRef.value.textValue = textValue }) diff --git a/packages/@headlessui-vue/src/components/popover/popover.test.ts b/packages/@headlessui-vue/src/components/popover/popover.test.ts index 7ba73f697d..3fabac6c15 100644 --- a/packages/@headlessui-vue/src/components/popover/popover.test.ts +++ b/packages/@headlessui-vue/src/components/popover/popover.test.ts @@ -1,4 +1,4 @@ -import { defineComponent, nextTick, ref, watch, h } from 'vue' +import { defineComponent, nextTick, ref, watch, h, ComponentOptionsWithoutProps } from 'vue' import { render } from '../../test-utils/vue-testing-library' import { Popover, PopoverGroup, PopoverButton, PopoverPanel, PopoverOverlay } from './popover' @@ -28,7 +28,7 @@ beforeAll(() => { afterAll(() => jest.restoreAllMocks()) -function renderTemplate(input: string | Partial[0]>) { +function renderTemplate(input: string | ComponentOptionsWithoutProps) { let defaultComponents = { Popover, PopoverGroup, @@ -345,9 +345,7 @@ describe('Rendering', () => { renderTemplate( html` - - Trigger - + Trigger ` ) @@ -361,14 +359,12 @@ describe('Rendering', () => { renderTemplate({ template: html` - - Trigger - + Trigger `, setup: () => ({ CustomButton: defineComponent({ - setup: props => () => h('button', { ...props }), + setup: (props) => () => h('button', { ...props }), }), }), }) @@ -383,9 +379,7 @@ describe('Rendering', () => { renderTemplate( html` - - Trigger - + Trigger ` ) @@ -399,14 +393,12 @@ describe('Rendering', () => { renderTemplate({ template: html` - - Trigger - + Trigger `, setup: () => ({ CustomButton: defineComponent({ - setup: props => () => h('div', props), + setup: (props) => () => h('div', props), }), }), }) @@ -569,9 +561,7 @@ describe('Rendering', () => { Trigger - - Link 1 - + Link 1 Link 2 @@ -757,9 +747,7 @@ describe('Composition', () => { Trigger - - {{JSON.stringify(data)}} - + {{JSON.stringify(data)}} `, @@ -787,9 +775,7 @@ describe('Composition', () => { Trigger - - {{JSON.stringify(data)}} - + {{JSON.stringify(data)}} `, diff --git a/packages/@headlessui-vue/src/components/popover/popover.ts b/packages/@headlessui-vue/src/components/popover/popover.ts index 2349ec2326..f4cba1b756 100644 --- a/packages/@headlessui-vue/src/components/popover/popover.ts +++ b/packages/@headlessui-vue/src/components/popover/popover.ts @@ -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) diff --git a/packages/@headlessui-vue/src/components/portal/portal.test.ts b/packages/@headlessui-vue/src/components/portal/portal.test.ts index ee03bab472..0c1055e783 100644 --- a/packages/@headlessui-vue/src/components/portal/portal.test.ts +++ b/packages/@headlessui-vue/src/components/portal/portal.test.ts @@ -1,4 +1,4 @@ -import { defineComponent, ref, nextTick } from 'vue' +import { defineComponent, ref, nextTick, ComponentOptionsWithoutProps } from 'vue' import { render } from '../../test-utils/vue-testing-library' import { Portal, PortalGroup } from './portal' @@ -22,7 +22,7 @@ beforeAll(() => { afterAll(() => jest.restoreAllMocks()) -function renderTemplate(input: string | Partial[0]>) { +function renderTemplate(input: string | ComponentOptionsWithoutProps) { let defaultComponents = { Portal, PortalGroup } if (typeof input === 'string') { @@ -108,12 +108,8 @@ it('should cleanup the Portal root when the last Portal is unmounted', async () renderTemplate({ template: html`
- - + +

Contents 1 ...

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

Contents 1 ...

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

Contents 1 ...

@@ -325,9 +309,7 @@ it('should be possible to force the Portal into a specific element using PortalG renderTemplate({ template: html`
- +
@@ -346,6 +328,6 @@ it('should be possible to force the Portal into a specific element using PortalG await new Promise(nextTick) expect(document.body.innerHTML).toMatchInlineSnapshot( - `"
B
"` + `"
B
"` ) }) diff --git a/packages/@headlessui-vue/src/components/radio-group/radio-group.test.ts b/packages/@headlessui-vue/src/components/radio-group/radio-group.test.ts index 1701836541..aacac780d7 100644 --- a/packages/@headlessui-vue/src/components/radio-group/radio-group.test.ts +++ b/packages/@headlessui-vue/src/components/radio-group/radio-group.test.ts @@ -1,4 +1,4 @@ -import { defineComponent, nextTick, ref, watch, reactive } from 'vue' +import { defineComponent, nextTick, ref, watch, reactive, ComponentOptionsWithoutProps } from 'vue' import { render } from '../../test-utils/vue-testing-library' import { RadioGroup, RadioGroupOption, RadioGroupLabel, RadioGroupDescription } from './radio-group' @@ -25,7 +25,7 @@ beforeAll(() => { afterAll(() => jest.restoreAllMocks()) function nextFrame() { - return new Promise(resolve => { + return new Promise((resolve) => { requestAnimationFrame(() => { requestAnimationFrame(() => { resolve() @@ -34,7 +34,7 @@ function nextFrame() { }) } -function renderTemplate(input: string | Partial[0]>) { +function renderTemplate(input: string | ComponentOptionsWithoutProps) { let defaultComponents = { RadioGroup, RadioGroupOption, RadioGroupLabel, RadioGroupDescription } if (typeof input === 'string') { @@ -86,9 +86,7 @@ describe('Safe guards', () => { it('should be possible to render a RadioGroup without options and without crashing', () => { renderTemplate({ - template: html` - - `, + template: html` `, setup() { let deliveryMethod = ref(undefined) return { deliveryMethod } diff --git a/packages/@headlessui-vue/src/components/radio-group/radio-group.ts b/packages/@headlessui-vue/src/components/radio-group/radio-group.ts index dba087a802..13557f2bbe 100644 --- a/packages/@headlessui-vue/src/components/radio-group/radio-group.ts +++ b/packages/@headlessui-vue/src/components/radio-group/radio-group.ts @@ -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) } diff --git a/packages/@headlessui-vue/src/components/switch/switch.test.tsx b/packages/@headlessui-vue/src/components/switch/switch.test.tsx index 7cc092f559..207239c57c 100644 --- a/packages/@headlessui-vue/src/components/switch/switch.test.tsx +++ b/packages/@headlessui-vue/src/components/switch/switch.test.tsx @@ -1,4 +1,4 @@ -import { defineComponent, ref, watch, h } from 'vue' +import { defineComponent, ref, watch, h, ComponentOptionsWithoutProps } from 'vue' import { render } from '../../test-utils/vue-testing-library' import { Switch, SwitchLabel, SwitchDescription, SwitchGroup } from './switch' @@ -16,7 +16,7 @@ import { suppressConsoleLogs } from '../../test-utils/suppress-console-logs' jest.mock('../../hooks/use-id') -function renderTemplate(input: string | Partial[0]>) { +function renderTemplate(input: string | ComponentOptionsWithoutProps) { let defaultComponents = { Switch, SwitchLabel, SwitchDescription, SwitchGroup } if (typeof input === 'string') { @@ -35,9 +35,7 @@ function renderTemplate(input: string | Partial { it('should be possible to render a Switch without crashing', () => { renderTemplate({ - template: html` - - `, + template: html` `, setup: () => ({ checked: ref(false) }), }) }) @@ -72,9 +70,7 @@ describe('Rendering', () => { it('should be possible to render an (on) Switch using an `as` prop', () => { renderTemplate({ - template: html` - - `, + template: html` `, setup: () => ({ checked: ref(true) }), }) assertSwitch({ state: SwitchState.On, tag: 'span' }) @@ -82,9 +78,7 @@ describe('Rendering', () => { it('should be possible to render an (off) Switch using an `as` prop', () => { renderTemplate({ - template: html` - - `, + template: html` `, setup: () => ({ checked: ref(false) }), }) assertSwitch({ state: SwitchState.Off, tag: 'span' }) @@ -106,11 +100,7 @@ describe('Rendering', () => { describe('`type` attribute', () => { it('should set the `type` to "button" by default', async () => { renderTemplate({ - template: html` - - Trigger - - `, + template: html` Trigger `, setup: () => ({ checked: ref(false) }), }) @@ -119,11 +109,7 @@ describe('Rendering', () => { it('should not set the `type` to "button" if it already contains a `type`', async () => { renderTemplate({ - template: html` - - Trigger - - `, + template: html` Trigger `, setup: () => ({ checked: ref(false) }), }) @@ -134,15 +120,11 @@ describe('Rendering', () => { 'should set the `type` to "button" when using the `as` prop which resolves to a "button"', suppressConsoleLogs(async () => { renderTemplate({ - template: html` - - Trigger - - `, + template: html` Trigger `, setup: () => ({ checked: ref(false), CustomButton: defineComponent({ - setup: props => () => h('button', { ...props }), + setup: (props) => () => h('button', { ...props }), }), }), }) @@ -155,11 +137,7 @@ describe('Rendering', () => { it('should not set the type if the "as" prop is not a "button"', async () => { renderTemplate({ - template: html` - - Trigger - - `, + template: html` Trigger `, setup: () => ({ checked: ref(false) }), }) @@ -170,15 +148,11 @@ describe('Rendering', () => { 'should not set the `type` to "button" when using the `as` prop which resolves to a "div"', suppressConsoleLogs(async () => { renderTemplate({ - template: html` - - Trigger - - `, + template: html` Trigger `, setup: () => ({ checked: ref(false), CustomButton: defineComponent({ - setup: props => () => h('div', props), + setup: (props) => () => h('div', props), }), }), }) @@ -213,9 +187,7 @@ describe('Render composition', () => { template: html` Label B - - Label A - + Label A `, setup: () => ({ checked: ref(false) }), @@ -234,9 +206,7 @@ describe('Render composition', () => { renderTemplate({ template: html` - - Label A - + Label A Label B `, @@ -370,9 +340,7 @@ describe('Keyboard interactions', () => { it('should be possible to toggle the Switch with Space', async () => { let handleChange = jest.fn() renderTemplate({ - template: html` - - `, + template: html` `, setup() { let checked = ref(false) watch([checked], () => handleChange(checked.value)) @@ -404,9 +372,7 @@ describe('Keyboard interactions', () => { it('should not be possible to use Enter to toggle the Switch', async () => { let handleChange = jest.fn() renderTemplate({ - template: html` - - `, + template: html` `, setup() { let checked = ref(false) watch([checked], () => handleChange(checked.value)) @@ -461,9 +427,7 @@ describe('Mouse interactions', () => { it('should be possible to toggle the Switch with a click', async () => { let handleChange = jest.fn() renderTemplate({ - template: html` - - `, + template: html` `, setup() { let checked = ref(false) watch([checked], () => handleChange(checked.value)) diff --git a/packages/@headlessui-vue/src/components/tabs/tabs.test.ts b/packages/@headlessui-vue/src/components/tabs/tabs.test.ts index e4573d0368..2ec3f3027a 100644 --- a/packages/@headlessui-vue/src/components/tabs/tabs.test.ts +++ b/packages/@headlessui-vue/src/components/tabs/tabs.test.ts @@ -1,4 +1,4 @@ -import { defineComponent, nextTick, ref } from 'vue' +import { ComponentOptionsWithoutProps, defineComponent, nextTick, ref } from 'vue' import { render } from '../../test-utils/vue-testing-library' import { TabGroup, TabList, Tab, TabPanels, TabPanel } from './tabs' import { suppressConsoleLogs } from '../../test-utils/suppress-console-logs' @@ -20,7 +20,7 @@ beforeAll(() => { afterAll(() => jest.restoreAllMocks()) -function renderTemplate(input: string | Partial[0]>) { +function renderTemplate(input: string | ComponentOptionsWithoutProps) { let defaultComponents = { TabGroup, TabList, Tab, TabPanels, TabPanel } if (typeof input === 'string') { diff --git a/packages/@headlessui-vue/src/components/tabs/tabs.ts b/packages/@headlessui-vue/src/components/tabs/tabs.ts index d7f8a1888c..4799dfb4b9 100644 --- a/packages/@headlessui-vue/src/components/tabs/tabs.ts +++ b/packages/@headlessui-vue/src/components/tabs/tabs.ts @@ -102,8 +102,8 @@ export let TabGroup = defineComponent({ if (api.tabs.value.length <= 0) return if (props.selectedIndex === null && selectedIndex.value !== null) return - let tabs = api.tabs.value.map(tab => dom(tab)).filter(Boolean) as HTMLElement[] - let focusableTabs = tabs.filter(tab => !tab.hasAttribute('disabled')) + let tabs = api.tabs.value.map((tab) => dom(tab)).filter(Boolean) as HTMLElement[] + let focusableTabs = tabs.filter((tab) => !tab.hasAttribute('disabled')) let indexToSet = props.selectedIndex ?? props.defaultIndex @@ -122,7 +122,7 @@ export let TabGroup = defineComponent({ let before = tabs.slice(0, indexToSet) let after = tabs.slice(indexToSet) - let next = [...after, ...before].find(tab => focusableTabs.includes(tab)) + let next = [...after, ...before].find((tab) => focusableTabs.includes(tab)) if (!next) return selectedIndex.value = tabs.indexOf(next) @@ -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() diff --git a/packages/@headlessui-vue/src/components/transitions/transition.test.ts b/packages/@headlessui-vue/src/components/transitions/transition.test.ts index fad8025c74..ea01ade06b 100644 --- a/packages/@headlessui-vue/src/components/transitions/transition.test.ts +++ b/packages/@headlessui-vue/src/components/transitions/transition.test.ts @@ -1,4 +1,4 @@ -import { defineComponent, ref, onMounted } from 'vue' +import { defineComponent, ref, onMounted, ComponentOptionsWithoutProps } from 'vue' import { render, fireEvent } from '../../test-utils/vue-testing-library' import { suppressConsoleLogs } from '../../test-utils/suppress-console-logs' @@ -11,7 +11,7 @@ jest.mock('../../hooks/use-id') afterAll(() => jest.restoreAllMocks()) -function renderTemplate(input: string | Partial[0]>) { +function renderTemplate(input: string | ComponentOptionsWithoutProps) { let defaultComponents = { TransitionRoot, TransitionChild } if (typeof input === 'string') { @@ -58,9 +58,7 @@ it('should render without crashing', () => { it('should be possible to render a Transition without children', () => { renderTemplate({ - template: html` - - `, + template: html` `, }) expect(document.getElementsByClassName('transition')).not.toBeNull() }) @@ -91,12 +89,10 @@ describe('Setup API', () => { describe('shallow', () => { it('should render a div and its children by default', () => { let { container } = renderTemplate({ - template: html` - Children - `, + template: html`Children`, }) - expect(container.firstChild).toMatchInlineSnapshot(html` + expect(container.firstChild).toMatchInlineSnapshot(`
Children
@@ -106,9 +102,7 @@ describe('Setup API', () => { it('should passthrough all the props (that we do not use internally)', () => { let { container } = renderTemplate({ template: html` - - Children - + Children `, }) @@ -124,11 +118,7 @@ describe('Setup API', () => { it('should render another component if the `as` prop is used and its children by default', () => { let { container } = renderTemplate({ - template: html` - - Children - - `, + template: html` Children `, }) expect(container.firstChild).toMatchInlineSnapshot(` @@ -159,9 +149,7 @@ describe('Setup API', () => { it('should render nothing when the show prop is false', () => { let { container } = renderTemplate({ - template: html` - Children - `, + template: html` Children `, }) expect(container.firstChild).toMatchInlineSnapshot(``) @@ -169,11 +157,7 @@ describe('Setup API', () => { it('should be possible to change the underlying DOM tag', () => { let { container } = renderTemplate({ - template: html` - - Children - - `, + template: html` Children `, }) expect(container.firstChild).toMatchInlineSnapshot(` @@ -470,9 +454,7 @@ describe('Transitions', () => { Hello!
- + `, setup() { let show = ref(false) @@ -525,9 +507,7 @@ describe('Transitions', () => { Hello!
- + `, setup() { let show = ref(false) @@ -580,9 +560,7 @@ describe('Transitions', () => { Hello! - + `, setup() { let show = ref(false) @@ -630,9 +608,7 @@ describe('Transitions', () => { Hello! - + `, setup() { let show = ref(false) @@ -687,9 +663,7 @@ describe('Transitions', () => { Hello! - + `, setup() { let show = ref(true) @@ -753,9 +727,7 @@ describe('Transitions', () => { Hello! - + `, setup() { let show = ref(true) @@ -822,9 +794,7 @@ describe('Transitions', () => { Hello! - + `, setup() { let show = ref(false) @@ -918,9 +888,7 @@ describe('Transitions', () => { Hello! - + `, setup() { let show = ref(false) @@ -1021,9 +989,7 @@ describe('Transitions', () => { - + `, setup() { let show = ref(true) @@ -1113,9 +1079,7 @@ describe('Transitions', () => { - + `, setup() { let show = ref(true) @@ -1227,9 +1191,7 @@ describe('Events', () => { Hello! - + `, setup() { let show = ref(false) diff --git a/packages/@headlessui-vue/src/components/transitions/transition.ts b/packages/@headlessui-vue/src/components/transitions/transition.ts index baed2a359f..46dd51b50e 100644 --- a/packages/@headlessui-vue/src/components/transitions/transition.ts +++ b/packages/@headlessui-vue/src/components/transitions/transition.ts @@ -31,7 +31,7 @@ import { type ID = ReturnType function splitClasses(classes: string = '') { - return classes.split(' ').filter(className => className.trim().length > 1) + return classes.split(' ').filter((className) => className.trim().length > 1) } interface TransitionContextValues { @@ -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 diff --git a/packages/@headlessui-vue/src/components/transitions/utils/transition.test.ts b/packages/@headlessui-vue/src/components/transitions/utils/transition.test.ts index 9918716179..58cd91a0aa 100644 --- a/packages/@headlessui-vue/src/components/transitions/utils/transition.test.ts +++ b/packages/@headlessui-vue/src/components/transitions/utils/transition.test.ts @@ -17,7 +17,7 @@ it('should be possible to transition', async () => { d.add( reportChanges( () => document.body.innerHTML, - content => { + (content) => { snapshots.push({ content, recordedAt: process.hrtime.bigint(), @@ -26,11 +26,11 @@ it('should be possible to transition', async () => { ) ) - await new Promise(resolve => { + await new Promise((resolve) => { transition(element, ['enter'], ['enterFrom'], ['enterTo'], ['entered'], resolve) }) - await new Promise(resolve => d.nextFrame(resolve)) + await new Promise((resolve) => d.nextFrame(resolve)) // Initial render: expect(snapshots[0].content).toEqual('
') @@ -61,7 +61,7 @@ it('should wait the correct amount of time to finish a transition', async () => d.add( reportChanges( () => document.body.innerHTML, - content => { + (content) => { snapshots.push({ content, recordedAt: process.hrtime.bigint(), @@ -70,11 +70,11 @@ it('should wait the correct amount of time to finish a transition', async () => ) ) - let reason = await new Promise(resolve => { + let reason = await new Promise((resolve) => { transition(element, ['enter'], ['enterFrom'], ['enterTo'], ['entered'], resolve) }) - await new Promise(resolve => d.nextFrame(resolve)) + await new Promise((resolve) => d.nextFrame(resolve)) expect(reason).toBe(Reason.Finished) // Initial render: @@ -118,7 +118,7 @@ it('should keep the delay time into account', async () => { d.add( reportChanges( () => document.body.innerHTML, - content => { + (content) => { snapshots.push({ content, recordedAt: process.hrtime.bigint(), @@ -127,11 +127,11 @@ it('should keep the delay time into account', async () => { ) ) - let reason = await new Promise(resolve => { + let reason = await new Promise((resolve) => { transition(element, ['enter'], ['enterFrom'], ['enterTo'], ['entered'], resolve) }) - await new Promise(resolve => d.nextFrame(resolve)) + await new Promise((resolve) => d.nextFrame(resolve)) expect(reason).toBe(Reason.Finished) let estimatedDuration = Number( @@ -161,7 +161,7 @@ it('should be possible to cancel a transition at any time', async () => { d.add( reportChanges( () => document.body.innerHTML, - content => { + (content) => { let recordedAt = process.hrtime.bigint() let total = snapshots.length @@ -178,16 +178,16 @@ it('should be possible to cancel a transition at any time', async () => { expect.assertions(2) // Setup the transition - let cancel = transition(element, ['enter'], ['enterFrom'], ['enterTo'], ['entered'], reason => { + let cancel = transition(element, ['enter'], ['enterFrom'], ['enterTo'], ['entered'], (reason) => { expect(reason).toBe(Reason.Cancelled) }) // Wait for a bit - await new Promise(resolve => setTimeout(resolve, 20)) + await new Promise((resolve) => setTimeout(resolve, 20)) // Cancel the transition cancel() - await new Promise(resolve => d.nextFrame(resolve)) + await new Promise((resolve) => d.nextFrame(resolve)) - expect(snapshots.map(snapshot => snapshot.content).join('\n')).not.toContain('enterTo') + expect(snapshots.map((snapshot) => snapshot.content).join('\n')).not.toContain('enterTo') }) diff --git a/packages/@headlessui-vue/src/components/transitions/utils/transition.ts b/packages/@headlessui-vue/src/components/transitions/utils/transition.ts index 8382141da9..008a01375a 100644 --- a/packages/@headlessui-vue/src/components/transitions/utils/transition.ts +++ b/packages/@headlessui-vue/src/components/transitions/utils/transition.ts @@ -22,13 +22,13 @@ function waitForTransition(node: HTMLElement, done: (reason: Reason) => void) { // Safari returns a comma separated list of values, so let's sort them and take the highest value. let { transitionDuration, transitionDelay } = getComputedStyle(node) - let [durationMs, delaysMs] = [transitionDuration, transitionDelay].map(value => { + let [durationMs, delaysMs] = [transitionDuration, transitionDelay].map((value) => { let [resolvedValue = 0] = value .split(',') // Remove falseys we can't work with .filter(Boolean) // Values are returned as `0.3s` or `75ms` - .map(v => (v.includes('ms') ? parseFloat(v) : parseFloat(v) * 1000)) + .map((v) => (v.includes('ms') ? parseFloat(v) : parseFloat(v) * 1000)) .sort((a, z) => z - a) return resolvedValue @@ -72,7 +72,7 @@ export function transition( addClasses(node, ...to) d.add( - waitForTransition(node, reason => { + waitForTransition(node, (reason) => { removeClasses(node, ...to, ...base) addClasses(node, ...entered) return _done(reason) diff --git a/packages/@headlessui-vue/src/hooks/use-focus-trap.ts b/packages/@headlessui-vue/src/hooks/use-focus-trap.ts index e5a070e721..034b64760e 100644 --- a/packages/@headlessui-vue/src/hooks/use-focus-trap.ts +++ b/packages/@headlessui-vue/src/hooks/use-focus-trap.ts @@ -75,7 +75,7 @@ export function useFocusTrap( onUnmounted(restore) // Handle Tab & Shift+Tab keyboard events - useWindowEvent('keydown', event => { + useWindowEvent('keydown', (event) => { if (!enabled.value) return if (event.key !== Keys.Tab) return if (!document.activeElement) return @@ -99,7 +99,7 @@ export function useFocusTrap( // Prevent programmatically escaping useWindowEvent( 'focus', - event => { + (event) => { if (!enabled.value) return if (containers.value.size !== 1) return diff --git a/packages/@headlessui-vue/src/hooks/use-inert-others.test.ts b/packages/@headlessui-vue/src/hooks/use-inert-others.test.ts index 46b5ed6643..3b82253a55 100644 --- a/packages/@headlessui-vue/src/hooks/use-inert-others.test.ts +++ b/packages/@headlessui-vue/src/hooks/use-inert-others.test.ts @@ -1,4 +1,4 @@ -import { defineComponent, ref, nextTick } from 'vue' +import { defineComponent, ref, nextTick, ComponentOptionsWithoutProps } from 'vue' import { render } from '../test-utils/vue-testing-library' import { useInertOthers } from './use-inert-others' @@ -14,7 +14,7 @@ beforeAll(() => { afterAll(() => jest.restoreAllMocks()) -function renderTemplate(input: string | Partial[0]>) { +function renderTemplate(input: string | ComponentOptionsWithoutProps) { let defaultComponents = {} if (typeof input === 'string') { @@ -35,16 +35,12 @@ function renderTemplate(input: string | Partialbefore
- `, + template: html`
before
`, }) let After = defineComponent({ name: 'After', - template: html` -
after
- `, + template: html`
after
`, }) it('should be possible to inert other elements', async () => { diff --git a/packages/@headlessui-vue/src/hooks/use-inert-others.ts b/packages/@headlessui-vue/src/hooks/use-inert-others.ts index ae85338561..5d28bf7d2a 100644 --- a/packages/@headlessui-vue/src/hooks/use-inert-others.ts +++ b/packages/@headlessui-vue/src/hooks/use-inert-others.ts @@ -32,7 +32,7 @@ export function useInertOthers( container: Ref, enabled: Ref = ref(true) ) { - watchEffect(onInvalidate => { + watchEffect((onInvalidate) => { if (!enabled.value) return if (!container.value) return @@ -50,7 +50,7 @@ export function useInertOthers( } // Collect direct children of the body - document.querySelectorAll(CHILDREN_SELECTOR).forEach(child => { + document.querySelectorAll(CHILDREN_SELECTOR).forEach((child) => { if (!(child instanceof HTMLElement)) return // Skip non-HTMLElements // Skip the interactables, and the parents of the interactables @@ -79,7 +79,7 @@ export function useInertOthers( // will become inert as well. if (interactables.size > 0) { // Collect direct children of the body - document.querySelectorAll(CHILDREN_SELECTOR).forEach(child => { + document.querySelectorAll(CHILDREN_SELECTOR).forEach((child) => { if (!(child instanceof HTMLElement)) return // Skip non-HTMLElements // Skip already inert parents diff --git a/packages/@headlessui-vue/src/hooks/use-tree-walker.ts b/packages/@headlessui-vue/src/hooks/use-tree-walker.ts index 9b216e337b..27f45bd5a2 100644 --- a/packages/@headlessui-vue/src/hooks/use-tree-walker.ts +++ b/packages/@headlessui-vue/src/hooks/use-tree-walker.ts @@ -24,6 +24,7 @@ export function useTreeWalker({ if (enabled !== undefined && !enabled.value) return let acceptNode = Object.assign((node: HTMLElement) => accept(node), { acceptNode: accept }) + // @ts-expect-error This `false` is a simple small fix for older browsers let walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, acceptNode, false) while (walker.nextNode()) walk(walker.currentNode as HTMLElement) diff --git a/packages/@headlessui-vue/src/hooks/use-window-event.ts b/packages/@headlessui-vue/src/hooks/use-window-event.ts index 8929c0dd89..987802e92e 100644 --- a/packages/@headlessui-vue/src/hooks/use-window-event.ts +++ b/packages/@headlessui-vue/src/hooks/use-window-event.ts @@ -7,7 +7,7 @@ export function useWindowEvent( ) { if (typeof window === 'undefined') return - watchEffect(onInvalidate => { + watchEffect((onInvalidate) => { window.addEventListener(type, listener, options) onInvalidate(() => { diff --git a/packages/@headlessui-vue/src/internal/stack-context.ts b/packages/@headlessui-vue/src/internal/stack-context.ts index 1f468469c3..595a8756fd 100644 --- a/packages/@headlessui-vue/src/internal/stack-context.ts +++ b/packages/@headlessui-vue/src/internal/stack-context.ts @@ -24,7 +24,7 @@ export function useStackContext() { export function useElemenStack(element: Ref | null) { let notify = useStackContext() - watchEffect(onInvalidate => { + watchEffect((onInvalidate) => { let domElement = element?.value if (!domElement) return diff --git a/packages/@headlessui-vue/src/test-utils/accessibility-assertions.ts b/packages/@headlessui-vue/src/test-utils/accessibility-assertions.ts index f478642b9a..d2ef0479ed 100644 --- a/packages/@headlessui-vue/src/test-utils/accessibility-assertions.ts +++ b/packages/@headlessui-vue/src/test-utils/accessibility-assertions.ts @@ -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') diff --git a/packages/@headlessui-vue/src/test-utils/execute-timeline.ts b/packages/@headlessui-vue/src/test-utils/execute-timeline.ts index 0fbec32088..5e9f9c7d08 100644 --- a/packages/@headlessui-vue/src/test-utils/execute-timeline.ts +++ b/packages/@headlessui-vue/src/test-utils/execute-timeline.ts @@ -18,7 +18,7 @@ function redentSnapshot(input: string) { return input .split('\n') - .map(line => + .map((line) => line.trim() === '---' ? line : line.replace(replacer, (_, sign, rest) => `${sign} ${rest}`) ) .join('\n') @@ -70,13 +70,13 @@ export async function executeTimeline( .reduce((total, current) => total + current, 0) // Changes happen in the next frame - await new Promise(resolve => d.nextFrame(resolve)) + await new Promise((resolve) => d.nextFrame(resolve)) // We wait for the amount of the duration - await new Promise(resolve => d.setTimeout(resolve, totalDuration)) + await new Promise((resolve) => d.setTimeout(resolve, totalDuration)) // We wait an additional next frame so that we know that we are done - await new Promise(resolve => d.nextFrame(resolve)) + await new Promise((resolve) => d.nextFrame(resolve)) }, Promise.resolve()) if (snapshots.length <= 0) { @@ -128,7 +128,7 @@ export async function executeTimeline( .replace(/Snapshot Diff:\n/g, '') ) .split('\n') - .map(line => ` ${line}`) + .map((line) => ` ${line}`) .join('\n')}` }) .filter(Boolean) diff --git a/packages/@headlessui-vue/src/test-utils/interactions.test.ts b/packages/@headlessui-vue/src/test-utils/interactions.test.ts index 3dab1e8a0f..990276d573 100644 --- a/packages/@headlessui-vue/src/test-utils/interactions.test.ts +++ b/packages/@headlessui-vue/src/test-utils/interactions.test.ts @@ -1,12 +1,12 @@ import { render } from './vue-testing-library' import { type, shift, Keys } from './interactions' -import { defineComponent, h } from 'vue' +import { ComponentOptionsWithoutProps, defineComponent, h } from 'vue' type Events = 'onKeydown' | 'onKeyup' | 'onKeypress' | 'onClick' | 'onBlur' | 'onFocus' let events: Events[] = ['onKeydown', 'onKeyup', 'onKeypress', 'onClick', 'onBlur', 'onFocus'] -function renderTemplate(input: string | Partial[0]>) { +function renderTemplate(input: string | ComponentOptionsWithoutProps) { let defaultComponents = {} if (typeof input === 'string') { @@ -164,7 +164,7 @@ describe('Keyboard', () => { let state = { readyToCapture: false } function createProps(id: string) { - return events.reduce( + return events.reduce void)>>( (props, name) => { props[name] = (event: any) => { if (!state.readyToCapture) return @@ -202,7 +202,7 @@ describe('Keyboard', () => { await type([key(input)]) - let expected = result.map(e => event(e)) + let expected = result.map((e) => event(e)) expect(fired.length).toEqual(result.length) diff --git a/packages/@headlessui-vue/src/test-utils/interactions.ts b/packages/@headlessui-vue/src/test-utils/interactions.ts index 8e93518bb1..600e605d1a 100644 --- a/packages/@headlessui-vue/src/test-utils/interactions.ts +++ b/packages/@headlessui-vue/src/test-utils/interactions.ts @@ -36,7 +36,7 @@ export function shift(event: Partial) { } export function word(input: string): Partial[] { - 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[], 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(',') diff --git a/packages/@headlessui-vue/src/test-utils/suppress-console-logs.ts b/packages/@headlessui-vue/src/test-utils/suppress-console-logs.ts index 8e63bfeb05..b2833c996a 100644 --- a/packages/@headlessui-vue/src/test-utils/suppress-console-logs.ts +++ b/packages/@headlessui-vue/src/test-utils/suppress-console-logs.ts @@ -5,10 +5,10 @@ type FunctionPropertyNames = { export function suppressConsoleLogs( cb: (...args: T) => void, - type: FunctionPropertyNames = 'warn' + type: FunctionPropertyNames = 'warn' ) { return (...args: T) => { - let spy = jest.spyOn(global.console, type).mockImplementation(jest.fn()) + let spy = jest.spyOn(globalThis.console, type).mockImplementation(jest.fn()) return new Promise((resolve, reject) => { Promise.resolve(cb(...args)).then(resolve, reject) diff --git a/packages/@headlessui-vue/src/utils/calculate-active-index.ts b/packages/@headlessui-vue/src/utils/calculate-active-index.ts index cc296a9068..16ed66ffb0 100644 --- a/packages/@headlessui-vue/src/utils/calculate-active-index.ts +++ b/packages/@headlessui-vue/src/utils/calculate-active-index.ts @@ -40,7 +40,7 @@ export function calculateActiveIndex( let nextActiveIndex = (() => { switch (action.focus) { case Focus.First: - return items.findIndex(item => !resolvers.resolveDisabled(item)) + return items.findIndex((item) => !resolvers.resolveDisabled(item)) case Focus.Previous: { let idx = items @@ -64,13 +64,13 @@ export function calculateActiveIndex( let idx = items .slice() .reverse() - .findIndex(item => !resolvers.resolveDisabled(item)) + .findIndex((item) => !resolvers.resolveDisabled(item)) if (idx === -1) return idx return items.length - 1 - idx } case Focus.Specific: - return items.findIndex(item => resolvers.resolveId(item) === action.id) + return items.findIndex((item) => resolvers.resolveId(item) === action.id) case Focus.Nothing: return null diff --git a/packages/@headlessui-vue/src/utils/focus-management.ts b/packages/@headlessui-vue/src/utils/focus-management.ts index c2dca21ae3..06ac5bd6d3 100644 --- a/packages/@headlessui-vue/src/utils/focus-management.ts +++ b/packages/@headlessui-vue/src/utils/focus-management.ts @@ -18,8 +18,8 @@ let focusableSelector = [ ? // TODO: Remove this once JSDOM fixes the issue where an element that is // "hidden" can be the document.activeElement, because this is not possible // in real browsers. - selector => `${selector}:not([tabindex='-1']):not([style*='display: none'])` - : selector => `${selector}:not([tabindex='-1'])` + (selector) => `${selector}:not([tabindex='-1']):not([style*='display: none'])` + : (selector) => `${selector}:not([tabindex='-1'])` ) .join(',') diff --git a/packages/@headlessui-vue/src/utils/match.ts b/packages/@headlessui-vue/src/utils/match.ts index 80496d12a2..c4becd32cd 100644 --- a/packages/@headlessui-vue/src/utils/match.ts +++ b/packages/@headlessui-vue/src/utils/match.ts @@ -12,7 +12,7 @@ export function match `"${key}"`) + .map((key) => `"${key}"`) .join(', ')}.` ) if (Error.captureStackTrace) Error.captureStackTrace(error, match) diff --git a/packages/@headlessui-vue/src/utils/render.test.ts b/packages/@headlessui-vue/src/utils/render.test.ts index 0bc0e026a8..287ce0ff30 100644 --- a/packages/@headlessui-vue/src/utils/render.test.ts +++ b/packages/@headlessui-vue/src/utils/render.test.ts @@ -1,4 +1,4 @@ -import { defineComponent } from 'vue' +import { defineComponent, ComponentOptionsWithoutProps } from 'vue' import { render as testRender } from '../test-utils/vue-testing-library' import { render } from './render' @@ -13,7 +13,7 @@ let Dummy = defineComponent({ }, }) -function renderTemplate(input: string | Partial[0]>) { +function renderTemplate(input: string | ComponentOptionsWithoutProps) { let defaultComponents = { Dummy } if (typeof input === 'string') { @@ -34,9 +34,7 @@ describe('Validation', () => { expect.hasAssertions() renderTemplate({ - template: html` - Contents - `, + template: html` Contents `, errorCaptured(err) { expect(err as Error).toEqual( new Error( diff --git a/packages/@headlessui-vue/src/utils/render.ts b/packages/@headlessui-vue/src/utils/render.ts index 27c3b77428..b8e3ffd3f8 100644 --- a/packages/@headlessui-vue/src/utils/render.ts +++ b/packages/@headlessui-vue/src/utils/render.ts @@ -98,7 +98,7 @@ function _render({ `However we need to passthrough the following props:`, Object.keys(passThroughProps) .concat(Object.keys(attrs)) - .map(line => ` - ${line}`) + .map((line) => ` - ${line}`) .join('\n'), '', 'You can apply a few solutions:', @@ -106,7 +106,7 @@ function _render({ 'Add an `as="..."` prop, to ensure that we render an actual element instead of a "template".', 'Render a single element as the child so that we can forward the props onto that element.', ] - .map(line => ` - ${line}`) + .map((line) => ` - ${line}`) .join('\n'), ].join('\n') ) diff --git a/packages/@headlessui-vue/tsconfig.json b/packages/@headlessui-vue/tsconfig.json index a62faa1a0b..cc575b4b35 100644 --- a/packages/@headlessui-vue/tsconfig.json +++ b/packages/@headlessui-vue/tsconfig.json @@ -24,7 +24,6 @@ "allowJs": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, - "noEmit": true, "resolveJsonModule": true, "isolatedModules": true }, diff --git a/packages/@headlessui-vue/tsconfig.tsdx.json b/packages/@headlessui-vue/tsconfig.tsdx.json deleted file mode 100644 index fc8520e737..0000000000 --- a/packages/@headlessui-vue/tsconfig.tsdx.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "./tsconfig.json" -} diff --git a/packages/@headlessui-vue/tsdx.config.js b/packages/@headlessui-vue/tsdx.config.js deleted file mode 100644 index 8a2668d598..0000000000 --- a/packages/@headlessui-vue/tsdx.config.js +++ /dev/null @@ -1,15 +0,0 @@ -const globals = { - vue: 'Vue', -} - -module.exports = { - rollup(config, opts) { - for (let key in globals) config.output.globals[key] = globals[key] - if (opts.format === 'esm') { - config = { ...config, preserveModules: true } - config.output = { ...config.output, dir: 'dist/', entryFileNames: '[name].esm.js' } - delete config.output.file - } - return config - }, -} diff --git a/packages/@headlessui-vue/types/jest.d.ts b/packages/@headlessui-vue/types/jest.d.ts new file mode 100644 index 0000000000..61902a8f06 --- /dev/null +++ b/packages/@headlessui-vue/types/jest.d.ts @@ -0,0 +1,9 @@ +export {} + +declare global { + namespace jest { + interface Matchers { + toBeWithinRenderFrame(actual: number): R + } + } +} diff --git a/packages/playground-react/package.json b/packages/playground-react/package.json index 40c43256a8..ad6f0012d6 100644 --- a/packages/playground-react/package.json +++ b/packages/playground-react/package.json @@ -1,17 +1,16 @@ { "name": "playground-react", - "version": "1.0.0", - "main": "next.config.js", + "private": true, + "version": "0.0.0", "scripts": { "prebuild": "yarn workspace @headlessui/react build", - "dev": "next dev", + "dev:headlessui": "yarn workspace @headlessui/react watch", + "dev:next": "next dev", + "dev": "npm-run-all -p dev:*", "build": "next build", - "start": "next start" + "start": "next start", + "clean": "rimraf ./.next" }, - "keywords": [], - "author": "Robin Malfait", - "license": "ISC", - "description": "", "dependencies": { "@headlessui/react": "*", "@popperjs/core": "^2.6.0", diff --git a/packages/playground-react/pages/_app.tsx b/packages/playground-react/pages/_app.tsx index 671e2ee472..ed848be441 100644 --- a/packages/playground-react/pages/_app.tsx +++ b/packages/playground-react/pages/_app.tsx @@ -113,13 +113,13 @@ function KeyCaster() { useEffect(() => { function handler(event: KeyboardEvent) { - setKeys(current => [ + setKeys((current) => [ event.shiftKey && event.key !== 'Shift' ? KeyDisplay[`Shift${event.key}`] ?? event.key : KeyDisplay[event.key] ?? event.key, ...current, ]) - d.setTimeout(() => setKeys(current => tap(current.slice(), clone => clone.pop())), 2000) + d.setTimeout(() => setKeys((current) => tap(current.slice(), (clone) => clone.pop())), 2000) } window.addEventListener('keydown', handler, true) @@ -129,11 +129,8 @@ function KeyCaster() { if (keys.length <= 0) return null return ( -
- {keys - .slice() - .reverse() - .join(' ')} +
+ {keys.slice().reverse().join(' ')}
) } @@ -162,8 +159,8 @@ function MyApp({ Component, pageProps }) { /> -
-
+
+
diff --git a/packages/playground-react/pages/_error.tsx b/packages/playground-react/pages/_error.tsx index 21c1a8adad..d20a86ce54 100644 --- a/packages/playground-react/pages/_error.tsx +++ b/packages/playground-react/pages/_error.tsx @@ -46,7 +46,7 @@ export default function Page(props: { examples: false | ExamplesType[] }) { export function Examples(props: { examples: ExamplesType[] }) { return (