From 4f7ef0cd683b210b586036a75b330274fe3192eb Mon Sep 17 00:00:00 2001 From: Milan Ricoul Date: Thu, 4 Apr 2024 17:10:56 +0200 Subject: [PATCH 1/3] fix (Dropdown): do not set aria-selected if only 1 list item --- src/classes/Dropdown.js | 24 +++++++++++++++++-- src/classes/Dropdown.test.js | 46 +++++++++++++++++++----------------- 2 files changed, 46 insertions(+), 24 deletions(-) diff --git a/src/classes/Dropdown.js b/src/classes/Dropdown.js index ebc5bec..1d813c5 100644 --- a/src/classes/Dropdown.js +++ b/src/classes/Dropdown.js @@ -196,10 +196,18 @@ class Dropdown extends AbstractDomElement { this.button.setAttribute('aria-expanded', 'true') - if (el.querySelectorAll('li[aria-selected="true"]').length === 1) { + const nodeListItems = el.querySelectorAll('li') + const nodeListSelectedItems = el.querySelectorAll('li[aria-selected="true"]') + + if (nodeListSelectedItems.length === 1) { this.updateFocusedListItem(el.querySelector('li[aria-selected="true"]')) - } else { + } + + if (nodeListSelectedItems.length === 0 && nodeListItems.length >= 1) { this.focusedElement = el.querySelector('li:first-child') + } + + if (this.focusedElement && nodeListSelectedItems.length === 0 && nodeListItems.length > 1) { this.focusedElement.setAttribute('aria-selected', 'true') } @@ -358,6 +366,12 @@ function handleKeydown(e) { function focusPreviousElement() { if (this.focusedElement && this.focusedElement.previousElementSibling) { this.updateFocusedListItem(this.focusedElement.previousElementSibling) + + return + } + + if (this.focusedElement) { + this.updateFocusedListItem(this.focusedElement) } } @@ -369,6 +383,12 @@ function focusPreviousElement() { function focusNextElement() { if (this.focusedElement && this.focusedElement.nextElementSibling) { this.updateFocusedListItem(this.focusedElement.nextElementSibling) + + return + } + + if (this.focusedElement) { + this.updateFocusedListItem(this.focusedElement) } } diff --git a/src/classes/Dropdown.test.js b/src/classes/Dropdown.test.js index 3a42ed3..e26da26 100644 --- a/src/classes/Dropdown.test.js +++ b/src/classes/Dropdown.test.js @@ -1,31 +1,33 @@ import { expect, test } from '@playwright/test' test.describe('Dropdown', () => { - test.beforeEach(async({page}) => { + test.beforeEach(async ({ page }) => { await page.goto('http://localhost:5173/examples/accessible-dropdown/index.html') }) - test('Click on the dropdown button, expect the listbox is visible.', async ({page}) => { + test('Click on the dropdown button, expect the listbox is visible.', async ({ page }) => { await page.click('#dropdown-1 button') - const display = await page.$eval( - '#dropdown-1 ul', - listbox => window.getComputedStyle(listbox).display - ) + const display = await page.$eval('#dropdown-1 ul', (listbox) => window.getComputedStyle(listbox).display) expect(display).toBe('block') }) - test('Click on the dropdown button, expect first list item has aria-selected attribute set to true.', async ({page}) => { + test('Click on the dropdown button, expect first list item has aria-selected attribute set to true.', async ({ + page, + }) => { await page.click('#dropdown-1 button') const hasValidAriaSelected = await page.$eval( '#dropdown-1 li:first-child', - firstListItem => firstListItem.hasAttribute('aria-selected') && firstListItem.getAttribute('aria-selected') === 'true' + (firstListItem) => + firstListItem.hasAttribute('aria-selected') && firstListItem.getAttribute('aria-selected') === 'true' ) expect(hasValidAriaSelected).toBe(true) }) - test('Focus the dropdown button, press Enter key once, press ArrowDown key twice, expect the third list item has aria-selected attribute set to true.', async ({page}) => { + test('Focus the dropdown button, press Enter key once, press ArrowDown key twice, expect the third list item has aria-selected attribute set to true.', async ({ + page, + }) => { await page.focus('#dropdown-1 button') await page.keyboard.down('Enter') await page.keyboard.down('ArrowDown') @@ -33,45 +35,45 @@ test.describe('Dropdown', () => { const hasValidAriaSelected = await page.$eval( '#dropdown-1 li:nth-child(3)', - thirdListItem => thirdListItem.hasAttribute('aria-selected') && thirdListItem.getAttribute('aria-selected') === 'true' + (thirdListItem) => + thirdListItem.hasAttribute('aria-selected') && thirdListItem.getAttribute('aria-selected') === 'true' ) expect(hasValidAriaSelected).toBe(true) }) - test('Focus the dropdown button, press Enter key, press End key, expect the last list item has aria-selected attribute set to true.', async ({page}) => { + test('Focus the dropdown button, press Enter key, press End key, expect the last list item has aria-selected attribute set to true.', async ({ + page, + }) => { await page.focus('#dropdown-1 button') await page.keyboard.down('Enter') await page.keyboard.down('End') const hasValidAriaSelected = await page.$eval( '#dropdown-1 li:last-child', - lastListItem => lastListItem.hasAttribute('aria-selected') && lastListItem.getAttribute('aria-selected') === 'true' + (lastListItem) => + lastListItem.hasAttribute('aria-selected') && lastListItem.getAttribute('aria-selected') === 'true' ) expect(hasValidAriaSelected).toBe(true) }) - test('Click on the dropdown button, click on the body, expect the listbox is not visible.', async ({page}) => { + test('Click on the dropdown button, click on the body, expect the listbox is not visible.', async ({ page }) => { await page.click('#dropdown-1 button') await page.click('body') - const display = await page.$eval( - '#dropdown-1 ul', - listbox => window.getComputedStyle(listbox).display - ) + const display = await page.$eval('#dropdown-1 ul', (listbox) => window.getComputedStyle(listbox).display) expect(display).toBe('none') }) - test('Focus the dropdown button, press Enter key, press Escape key, expect the listbox is not visible.', async ({page}) => { + test('Focus the dropdown button, press Enter key, press Escape key, expect the listbox is not visible.', async ({ + page, + }) => { await page.focus('#dropdown-1 button') await page.keyboard.down('Enter') await page.keyboard.down('Escape') - const display = await page.$eval( - '#dropdown-1 ul', - listbox => window.getComputedStyle(listbox).display - ) + const display = await page.$eval('#dropdown-1 ul', (listbox) => window.getComputedStyle(listbox).display) expect(display).toBe('none') }) From 8b62ce95f7b911dfe5d32c712608722c5b683901 Mon Sep 17 00:00:00 2001 From: mricoul Date: Thu, 4 Apr 2024 17:36:42 +0200 Subject: [PATCH 2/3] docs (CHANGELOG): add change log for 1.5.4 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 13e6e0c..5945b21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 1.5.4 - 2024-04-04 + +- Add support for 1 list item dropdown + ## 1.5.3 - 2024-03-21 - Add `aria-expanded="false"` attribute to button on init and remove it on destroy for Toggle class. From 37da3eaad701dbc94aced1e14f073698d801a2c4 Mon Sep 17 00:00:00 2001 From: mricoul Date: Thu, 4 Apr 2024 17:37:00 +0200 Subject: [PATCH 3/3] chore (package): bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f3ac6cf..b01a94d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@beapi/be-a11y", - "version": "1.5.3", + "version": "1.5.4", "type": "module", "description": "Collection of usefull accessible components", "repository": {