diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..18e38c6 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,32 @@ +# Changelog + + + +## [4.0.0] - 2023-07-26 + +- Update for swup 4 compatibility + +## [3.0.0] - 2023-03-10 + +- Switch to microbundle +- Export native ESM module + +## [2.1.0] - 2022-08-21 + +- Set `aria-busy` on html element during transitions + +## [2.0.0] - 2021-03-15 + +- Fix bundle name + +## [1.0.0] - 2020-08-10 + +- Initial release + +[Unreleased]: https://github.com/swup/a11y-plugin/compare/4.0.0...HEAD + +[4.0.0]: https://github.com/swup/a11y-plugin/releases/tag/4.0.0 +[3.0.0]: https://github.com/swup/a11y-plugin/releases/tag/3.0.0 +[2.1.0]: https://github.com/swup/a11y-plugin/releases/tag/2.1.0 +[2.0.0]: https://github.com/swup/a11y-plugin/releases/tag/2.0.0 +[1.0.0]: https://github.com/swup/a11y-plugin/releases/tag/1.0.0 diff --git a/readme.md b/README.md similarity index 75% rename from readme.md rename to README.md index 790e031..c5d548f 100755 --- a/readme.md +++ b/README.md @@ -1,37 +1,29 @@ # Swup A11y Plugin -**by [daun](https://github.com/daun)** +A [swup](https://swup.js.org) plugin for enhanced accessibility. -Enhance the accessibility of your [swup](https://github.com/swup/swup)-powered -sites. - -Loading new content via AJAX is great UX for most users, but comes with serious -shortcomings for screen reader users. We can improve the experience for -everybody if we: +Loading new content via AJAX is a great experience for most users, but comes with serious +shortcomings for screen reader users. This plugin will improve that: - **Announce page visits** to screenreaders by reading the new page title - **Focus the main content area** after swapping out the content -That's exactly what this plugin does. - ## Installation -This plugin can be installed with npm +Install the plugin from npm and import it into your bundle. ```bash npm install @swup/a11y-plugin ``` -and included with import - -```shell +```js import SwupA11yPlugin from '@swup/a11y-plugin'; ``` -or included from the dist folder +Or include the minified production file from a CDN: ```html - + ``` ## Usage @@ -60,6 +52,12 @@ See the options below for customizing what elements to look for. ``` +If you want the announcement to be different from the text content, use `aria-label`: + +```html +

Project Title

+``` + ## Styling Browsers will display a visible outline around the main content area when it @@ -95,8 +93,7 @@ This area will receive focus after a new page was loaded. The selector for finding headings **inside the main content area**. -The first heading's content will be read to screen readers after a new page was -loaded. +The first heading's content will be read to screen readers after a new page was loaded. ### announcementTemplate diff --git a/package-lock.json b/package-lock.json index 001cb20..9c351cb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,20 +1,20 @@ { "name": "@swup/a11y-plugin", - "version": "2.1.0", + "version": "4.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@swup/a11y-plugin", - "version": "2.1.0", + "version": "4.0.0", "license": "MIT", "dependencies": { - "@swup/plugin": "^2.0.0", + "@swup/plugin": "^3.0.0", "focus-options-polyfill": "^1.5.0", "on-demand-live-region": "^0.1.3" }, "peerDependencies": { - "swup": "^3.0.0" + "swup": "^4.0.0" } }, "node_modules/@ampproject/remapping": { @@ -1934,9 +1934,9 @@ "integrity": "sha512-/3nBqG7LqmK1uqaCSTA6s2NwQBDQXNyLAFBzlX6uaxqjIQcAZyq6K+sgcQ40oj02Vn/2mLSkeL9DOfP7BPOwVA==" }, "node_modules/@swup/plugin": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@swup/plugin/-/plugin-2.0.2.tgz", - "integrity": "sha512-pde/zKIgXpbI+qy8rhuy8De8KniZRuwAoxuOoGTvhErolrW2khlYKtVXgPACRmmPJvGI5ZTfBzBN5txKfIGefQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@swup/plugin/-/plugin-3.0.0.tgz", + "integrity": "sha512-dCFhmFmucMY4ae4qo01fGocU74YrLwffTTtxCUO21OyDgFdywjO4RLP0pgjsiXueBbpcXkexbj4q+O19dWQRoA==", "dependencies": { "@swup/browserslist-config": "^1.0.0", "@swup/prettier-config": "^1.0.0", @@ -1945,7 +1945,7 @@ "prettier": "^2.7.1", "shelljs": "^0.8.5", "shelljs-live": "^0.0.5", - "swup": "^3.0.0" + "swup": "^4.0.0" }, "bin": { "swup-plugin": "bin/swup-plugin.js" @@ -2577,11 +2577,14 @@ } }, "node_modules/delegate-it": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/delegate-it/-/delegate-it-3.0.1.tgz", - "integrity": "sha512-XU8H4pjDGBW74hFIbjdLPnvtU3HF3P9bbZvoFBSBLb5JgNaTkRb/2lvC1V+9kmZsxVR0kad4bU3rYhQ/4Ij+Gw==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/delegate-it/-/delegate-it-6.0.1.tgz", + "integrity": "sha512-ZS2hRm/SaoPzaeWcWyYjzVVF4/PgALZqma9FXsunFt4XQGVAtQ79Vx7v57vNQNaI75Rl12C+x6TkLqHS5PNKLg==", "dependencies": { - "typed-query-selector": "^2.6.1" + "typed-query-selector": "^2.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/fregante" } }, "node_modules/dom-serializer": { @@ -4146,6 +4149,11 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, + "node_modules/path-to-regexp": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", + "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==" + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -5390,13 +5398,14 @@ } }, "node_modules/swup": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/swup/-/swup-3.0.5.tgz", - "integrity": "sha512-MD2oVgyvKbUgWeGKjOzDQUfYLtqlQktREcR27QnzqKBSAjApLrbMTWToYrkI2ZnCXG6ApPMjsrRLArSwiJUBmw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/swup/-/swup-4.0.0.tgz", + "integrity": "sha512-GQX9WKFJBe4mZaryKkb8QZHsVP9u0GbMauD/B/msthNFB7rbUOqO1eSvaZB9d4TypHCjbviZ6kKac0v9vChOOA==", "hasInstallScript": true, "dependencies": { - "delegate-it": "^3.0.1", - "opencollective-postinstall": "^2.0.2" + "delegate-it": "^6.0.0", + "opencollective-postinstall": "^2.0.2", + "path-to-regexp": "^6.2.1" } }, "node_modules/terser": { @@ -5457,9 +5466,9 @@ } }, "node_modules/typed-query-selector": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.9.2.tgz", - "integrity": "sha512-mOnelGQ0JBbYvboX6v/3vijUkIW9L557DHVRUFQTKG352EWvW/uDN6ORlPvTPRivefqb3QbbyZgLtPmxQaxmug==" + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.11.0.tgz", + "integrity": "sha512-qBs4sfmnLlPOyo2oSdvHbIFHe2CPgU54/1UGfSNceb7LARpIEVxUaeRX0Doje6oKpuySS2stqy90R3YrynR8Kg==" }, "node_modules/typescript": { "version": "4.9.5", diff --git a/package.json b/package.json index 99a8cb0..239c991 100755 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "@swup/a11y-plugin", "amdName": "SwupA11yPlugin", - "version": "3.0.0", - "description": "Enhanced accessibility for swup-powered sites", + "version": "4.0.0", + "description": "A swup plugin for enhanced accessibility", "type": "module", "source": "src/index.js", "main": "./dist/index.cjs", @@ -17,7 +17,7 @@ "dev": "swup-plugin dev", "lint": "swup-plugin lint", "format": "swup-plugin format", - "prepublish": "npm run build" + "prepublishOnly": "npm run build" }, "author": { "name": "Philipp Daun", @@ -42,12 +42,12 @@ "url": "https://github.com/swup/a11y-plugin.git" }, "dependencies": { - "@swup/plugin": "^2.0.0", + "@swup/plugin": "^3.0.0", "focus-options-polyfill": "^1.5.0", "on-demand-live-region": "^0.1.3" }, "peerDependencies": { - "swup": "^3.0.0" + "swup": "^4.0.0" }, "browserslist": [ "extends @swup/browserslist-config" diff --git a/src/index.js b/src/index.js index 5fdbf87..4fc298e 100755 --- a/src/index.js +++ b/src/index.js @@ -6,46 +6,47 @@ import 'focus-options-polyfill'; export default class SwupA11yPlugin extends Plugin { name = 'SwupA11yPlugin'; + requires = { swup: '>=4' }; + + defaults = { + contentSelector: 'main', + headingSelector: 'h1, h2, [role=heading]', + announcementTemplate: 'Navigated to: {title}', + urlTemplate: 'New page at {url}' + }; + constructor(options = {}) { super(); - this.options = { - contentSelector: 'main', - headingSelector: 'h1, h2, [role=heading]', - announcementTemplate: 'Navigated to: {title}', - urlTemplate: 'New page at {url}', - ...options - }; + this.options = { ...this.defaults, ...options }; this.liveRegion = new OnDemandLiveRegion(); } mount() { - this.swup.on('contentReplaced', this.announceVisit); - this.swup.on('transitionStart', this.onTransitionStart); - this.swup.on('transitionEnd', this.onTransitionEnd); + this.on('visit:start', this.markAsBusy); + this.on('visit:end', this.unmarkAsBusy); + this.on('content:replace', this.announceVisit); + } + + markAsBusy() { + document.documentElement.setAttribute('aria-busy', 'true'); } - unmount() { - this.swup.off('contentReplaced', this.announceVisit); - this.swup.off('transitionStart', this.onTransitionStart); - this.swup.off('transitionEnd', this.onTransitionEnd); + unmarkAsBusy() { + document.documentElement.removeAttribute('aria-busy'); } - announceVisit = () => { + announceVisit() { requestAnimationFrame(() => { this.announcePageName(); this.focusPageContent(); - }); - }; + }) + } - announcePageName = () => { - const { - contentSelector, - headingSelector, - urlTemplate, - announcementTemplate - } = this.options; + announcePageName() { + const { contentSelector, headingSelector, urlTemplate, announcementTemplate } = + this.options; // Default: announce new /path/of/page.html let pageName = urlTemplate.replace('{url}', window.location.pathname); @@ -67,21 +68,13 @@ export default class SwupA11yPlugin extends Plugin { const announcement = announcementTemplate.replace('{title}', pageName.trim()); this.liveRegion.say(announcement); - }; + } - focusPageContent = () => { + focusPageContent() { const content = document.querySelector(this.options.contentSelector); if (content) { content.setAttribute('tabindex', '-1'); content.focus({ preventScroll: true }); } - }; - - onTransitionStart = () => { - document.documentElement.setAttribute('aria-busy', 'true'); - }; - - onTransitionEnd = () => { - document.documentElement.removeAttribute('aria-busy'); - }; + } }