From fbad8ba23ef31369775a30dbbcc4566828b3aba1 Mon Sep 17 00:00:00 2001 From: Joshua Graber <68428039+joshuagraber@users.noreply.github.com> Date: Tue, 18 Jun 2024 09:40:39 -0400 Subject: [PATCH] ci: add accessibility linting and fix existing issues (#90) resolves #89 BREAKING CHANGE Not actually breaking changes, but `2.7.0` should have been a major release (force-pushing mucked things up) so we add it here to bump. --- eslint-config/index.js | 38 ++++++- eslint-config/package.json | 8 +- package-lock.json | 107 +++++++++++++++++- package.json | 6 +- .../Breadcrumbs/PdapBreadcrumbs.vue | 22 ++-- .../__snapshots__/breadcrumbs.spec.ts.snap | 4 +- src/components/Button/PdapButton.vue | 2 +- src/components/Dropdown/PdapDropdown.vue | 27 +++-- .../__snapshots__/PdapDropdown.spec.ts.snap | 8 +- src/components/Footer/PdapFooter.vue | 13 ++- .../Footer/__snapshots__/footer.spec.ts.snap | 2 +- src/components/Header/PdapHeader.vue | 19 ++-- .../Header/__snapshots__/header.spec.ts.snap | 42 +++---- src/components/Nav/PdapNav.vue | 104 ++++++++++------- .../Nav/__snapshots__/nav.spec.ts.snap | 42 +++---- src/components/Nav/nav.spec.ts | 4 +- src/components/Nav/types.ts | 5 - src/components/Spinner/PdapSpinner.vue | 25 ++-- .../__snapshots__/spinner.spec.ts.snap | 6 +- src/config/index.ts | 38 +++++++ stylelint.config.mjs | 18 ++- 21 files changed, 384 insertions(+), 156 deletions(-) diff --git a/eslint-config/index.js b/eslint-config/index.js index c41af4a..60ac4df 100644 --- a/eslint-config/index.js +++ b/eslint-config/index.js @@ -7,11 +7,12 @@ module.exports = { 'plugin:vue/vue3-recommended', 'plugin:vue/strongly-recommended', '@vue/eslint-config-prettier', + 'plugin:vuejs-accessibility/recommended' ], env: { node: true }, - plugins: ['prettier'], + plugins: ['prettier', 'vuejs-accessibility'], rules: { 'vue/require-default-prop': 'off', indent: 'off', @@ -41,9 +42,42 @@ module.exports = { tabWidth: 2, useTabs: true, singleQuote: true, - quotes: [2, "single", { "avoidEscape": true }] + quotes: [2, 'single', { 'avoidEscape': true }] }, ], 'vue/no-multiple-template-root': 'off', + 'vuejs-accessibility/alt-text': [ + 'error', + { + 'elements': ['img', 'object', 'area', 'input[type="image"]'], + 'img': ['Image'], + 'object': ['Object'], + 'area': ['Area'], + 'input[type=\'image\']': ['ImageInput'] + } + ], + "vuejs-accessibility/no-redundant-roles": [ + "error", + { + "nav": ["navigation"], + } + ], + "vuejs-accessibility/media-has-caption": [ + "error", + { + "audio": ["Audio"], + "video": ["Video"], + "track": ["Track"] + } + ], + "vuejs-accessibility/label-has-for": [ + "error", + { + "required": { + "some": ["nesting", "id"] + }, + "allowChildren": true + } + ] }, }; diff --git a/eslint-config/package.json b/eslint-config/package.json index f57a7a6..f0048be 100644 --- a/eslint-config/package.json +++ b/eslint-config/package.json @@ -1,6 +1,6 @@ { "name": "@pdap-design-system/eslint-config", - "version": "1.0.0", + "version": "1.0.2", "description": "eslint config for PDAP client apps", "main": "index.js", "type": "commonjs", @@ -16,5 +16,9 @@ "homepage": "https://github.com/Police-Data-Accessibility-Project/design-system#readme", "peerDependencies": { "eslint": ">= 8" + }, + "devDependencies": { + "@ronilaukkarinen/stylelint-a11y": "^1.2.9", + "eslint-plugin-vuejs-accessibility": "^2.3.0" } -} +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index dade584..bbacb0f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,7 +23,7 @@ "devDependencies": { "@commitlint/cli": "^18.4.3", "@commitlint/config-conventional": "^18.4.3", - "@pdap-design-system/eslint-config": "^1.0.0", + "@pdap-design-system/eslint-config": "^1.0.1", "@semantic-release/changelog": "^6.0.3", "@semantic-release/git": "^10.0.1", "@semantic-release/release-notes-generator": "^12.1.0", @@ -68,8 +68,12 @@ }, "eslint-config": { "name": "@pdap-design-system/eslint-config", - "version": "1.0.0", + "version": "1.0.2", "license": "MIT", + "devDependencies": { + "@ronilaukkarinen/stylelint-a11y": "^1.2.9", + "eslint-plugin-vuejs-accessibility": "^2.3.0" + }, "peerDependencies": { "eslint": ">= 8" } @@ -1862,6 +1866,18 @@ "node": ">=12" } }, + "node_modules/@ronilaukkarinen/stylelint-a11y": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@ronilaukkarinen/stylelint-a11y/-/stylelint-a11y-1.2.9.tgz", + "integrity": "sha512-8w0mWEO6B16J4PSc9lMkNUsVsD+lbmgsQiYOY0Xq/FTUzHF0/DM4eR/PLXBFgcz9hENTnLzGBM7zEVOsC1vCIg==", + "dev": true, + "engines": { + "node": ">=8.7.0" + }, + "peerDependencies": { + "stylelint": "10 - 15" + } + }, "node_modules/@semantic-release/changelog": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/@semantic-release/changelog/-/changelog-6.0.3.tgz", @@ -3481,6 +3497,15 @@ "integrity": "sha512-F2+Hkm9xFaRg+GkaNnbwXNDV5O6pnCFEmqyhvfC/Ic5LbgOWjJh3L+mN/s91rxVL3znE7DYVpW0GJFT+4YBgWw==", "dev": true }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "dependencies": { + "dequal": "^2.0.3" + } + }, "node_modules/array-buffer-byte-length": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", @@ -5174,6 +5199,15 @@ "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", "dev": true }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/detect-file": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", @@ -5783,6 +5817,29 @@ "node": ">=10" } }, + "node_modules/eslint-plugin-vuejs-accessibility": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vuejs-accessibility/-/eslint-plugin-vuejs-accessibility-2.3.0.tgz", + "integrity": "sha512-zQ6IzK+3obZzPsjeVUeL3xAUlMHXZgRZ8vgXvQAmoZVbsp1xZe6UwXIKUFIim5h3tq/7bOLgei09GoBjJQs+Cw==", + "dev": true, + "dependencies": { + "aria-query": "^5.3.0", + "emoji-regex": "^10.0.0", + "vue-eslint-parser": "^9.0.1" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-vuejs-accessibility/node_modules/emoji-regex": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "dev": true + }, "node_modules/eslint-scope": { "version": "7.2.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", @@ -18358,7 +18415,10 @@ }, "@pdap-design-system/eslint-config": { "version": "file:eslint-config", - "requires": {} + "requires": { + "@ronilaukkarinen/stylelint-a11y": "^1.2.9", + "eslint-plugin-vuejs-accessibility": "^2.3.0" + } }, "@pkgjs/parseargs": { "version": "0.11.0", @@ -18415,6 +18475,13 @@ "config-chain": "^1.1.11" } }, + "@ronilaukkarinen/stylelint-a11y": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@ronilaukkarinen/stylelint-a11y/-/stylelint-a11y-1.2.9.tgz", + "integrity": "sha512-8w0mWEO6B16J4PSc9lMkNUsVsD+lbmgsQiYOY0Xq/FTUzHF0/DM4eR/PLXBFgcz9hENTnLzGBM7zEVOsC1vCIg==", + "dev": true, + "requires": {} + }, "@semantic-release/changelog": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/@semantic-release/changelog/-/changelog-6.0.3.tgz", @@ -19565,6 +19632,15 @@ "integrity": "sha512-F2+Hkm9xFaRg+GkaNnbwXNDV5O6pnCFEmqyhvfC/Ic5LbgOWjJh3L+mN/s91rxVL3znE7DYVpW0GJFT+4YBgWw==", "dev": true }, + "aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "requires": { + "dequal": "^2.0.3" + } + }, "array-buffer-byte-length": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", @@ -20755,6 +20831,12 @@ "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", "dev": true }, + "dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true + }, "detect-file": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", @@ -21259,6 +21341,25 @@ } } }, + "eslint-plugin-vuejs-accessibility": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vuejs-accessibility/-/eslint-plugin-vuejs-accessibility-2.3.0.tgz", + "integrity": "sha512-zQ6IzK+3obZzPsjeVUeL3xAUlMHXZgRZ8vgXvQAmoZVbsp1xZe6UwXIKUFIim5h3tq/7bOLgei09GoBjJQs+Cw==", + "dev": true, + "requires": { + "aria-query": "^5.3.0", + "emoji-regex": "^10.0.0", + "vue-eslint-parser": "^9.0.1" + }, + "dependencies": { + "emoji-regex": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "dev": true + } + } + }, "eslint-scope": { "version": "7.2.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", diff --git a/package.json b/package.json index 76dec75..acac0a1 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "devDependencies": { "@commitlint/cli": "^18.4.3", "@commitlint/config-conventional": "^18.4.3", - "@pdap-design-system/eslint-config": "^1.0.0", + "@pdap-design-system/eslint-config": "^1.0.1", "@semantic-release/changelog": "^6.0.3", "@semantic-release/git": "^10.0.1", "@semantic-release/release-notes-generator": "^12.1.0", @@ -103,7 +103,7 @@ "clean:test": "rimraf coverage", "lint": "run-p lint:*", "lint:css": "stylelint 'src/**/*.{css,vue}'", - "lint:es": "eslint src --ext .ts .", + "lint:es": "eslint --ext .ts,.vue src", "lint:ts": "vue-tsc", "postbuild": "rimraf dist/{config,utils}", "posttest": "npm run clean:test", @@ -135,4 +135,4 @@ "path": "./node_modules/cz-conventional-changelog" } } -} \ No newline at end of file +} diff --git a/src/components/Breadcrumbs/PdapBreadcrumbs.vue b/src/components/Breadcrumbs/PdapBreadcrumbs.vue index e7e32e2..b299d6d 100644 --- a/src/components/Breadcrumbs/PdapBreadcrumbs.vue +++ b/src/components/Breadcrumbs/PdapBreadcrumbs.vue @@ -1,6 +1,6 @@ @@ -31,27 +31,28 @@ const props = withDefaults(defineProps(), { logoImageAnchorPath: '/', }); -// State -const height = ref(); - // Vars const el = ref(null); const navLogoLinkIsPath = props.logoImageAnchorPath.startsWith('/'); // Lifecycle methods onMounted(() => { - getHeight(); - window.addEventListener('resize', getHeight); + console.debug('on mounted'); + getHeightAndSetToCSSVar(); + window.addEventListener('resize', getHeightAndSetToCSSVar); }); onBeforeUnmount(() => { - window.removeEventListener('resize', getHeight); + window.removeEventListener('resize', getHeightAndSetToCSSVar); }); // Utils -function getHeight() { +function getHeightAndSetToCSSVar() { if (el.value) { - height.value = el.value.offsetHeight; + (document.querySelector(':root') as HTMLElement)?.style.setProperty( + '--header-height', + `${el.value.clientHeight}px` + ); } } diff --git a/src/components/Header/__snapshots__/header.spec.ts.snap b/src/components/Header/__snapshots__/header.spec.ts.snap index d69f6f2..abcac5b 100644 --- a/src/components/Header/__snapshots__/header.spec.ts.snap +++ b/src/components/Header/__snapshots__/header.spec.ts.snap @@ -3,29 +3,31 @@ exports[`Header component > Renders a header 1`] = `
-
- + - + + +
`; diff --git a/src/components/Nav/PdapNav.vue b/src/components/Nav/PdapNav.vue index b70d231..7c86e52 100644 --- a/src/components/Nav/PdapNav.vue +++ b/src/components/Nav/PdapNav.vue @@ -1,12 +1,22 @@