fix(accordion): navigating with tab confuses the arrow key navigation (#2056)

* fix(accordion): Handle focusin event, when tabbing to an invoker

* fix(accordion): Add changeset

* fix(accordion): Test if the index equals to the focusedIndex
This commit is contained in:
Gyulai Levente 2023-09-11 14:43:52 +02:00 committed by GitHub
parent 9b9485dbaa
commit 857d47a933
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 35 additions and 2 deletions

View file

@ -0,0 +1,5 @@
---
'@lion/ui': patch
---
Handle focusin event in invokers in LionAccordion. Fix tabbing issues.

View file

@ -10,6 +10,7 @@ import { uuid } from '@lion/ui/core.js';
* @property {HTMLElement} content content node * @property {HTMLElement} content content node
* @property {(event: Event) => unknown} clickHandler executed on click event * @property {(event: Event) => unknown} clickHandler executed on click event
* @property {(event: Event) => unknown} keydownHandler executed on keydown event * @property {(event: Event) => unknown} keydownHandler executed on keydown event
* @property {(event: Event) => unknown} focusHandler executed on focusin event
*/ */
/** /**
@ -197,6 +198,7 @@ export class LionAccordion extends LitElement {
content, content,
clickHandler: this.__createInvokerClickHandler(index), clickHandler: this.__createInvokerClickHandler(index),
keydownHandler: this.__handleInvokerKeydown.bind(this), keydownHandler: this.__handleInvokerKeydown.bind(this),
focusHandler: this.__createInvokerFocusHandler(index),
}; };
this._setupContent(entry); this._setupContent(entry);
this._setupInvoker(entry); this._setupInvoker(entry);
@ -248,6 +250,19 @@ export class LionAccordion extends LitElement {
}; };
} }
/**
* @param {number} index
* @private
*/
__createInvokerFocusHandler(index) {
return () => {
if (index === this.focusedIndex) {
return;
}
this.focusedIndex = index;
};
}
/** /**
* @param {Event} e * @param {Event} e
* @private * @private
@ -304,7 +319,7 @@ export class LionAccordion extends LitElement {
* @protected * @protected
*/ */
_setupInvoker(entry) { _setupInvoker(entry) {
const { invoker, uid, index, clickHandler, keydownHandler } = entry; const { invoker, uid, index, clickHandler, keydownHandler, focusHandler } = entry;
invoker.style.setProperty('order', `${index + 1}`); invoker.style.setProperty('order', `${index + 1}`);
const firstChild = invoker.firstElementChild; const firstChild = invoker.firstElementChild;
if (firstChild) { if (firstChild) {
@ -312,6 +327,7 @@ export class LionAccordion extends LitElement {
firstChild.setAttribute('aria-controls', `content-${uid}`); firstChild.setAttribute('aria-controls', `content-${uid}`);
firstChild.addEventListener('click', clickHandler); firstChild.addEventListener('click', clickHandler);
firstChild.addEventListener('keydown', keydownHandler); firstChild.addEventListener('keydown', keydownHandler);
firstChild.addEventListener('focusin', focusHandler);
} }
} }
@ -320,13 +336,14 @@ export class LionAccordion extends LitElement {
* @protected * @protected
*/ */
_cleanInvoker(entry) { _cleanInvoker(entry) {
const { invoker, clickHandler, keydownHandler } = entry; const { invoker, clickHandler, keydownHandler, focusHandler } = entry;
const firstChild = invoker.firstElementChild; const firstChild = invoker.firstElementChild;
if (firstChild) { if (firstChild) {
firstChild.removeAttribute('id'); firstChild.removeAttribute('id');
firstChild.removeAttribute('aria-controls'); firstChild.removeAttribute('aria-controls');
firstChild.removeEventListener('click', clickHandler); firstChild.removeEventListener('click', clickHandler);
firstChild.removeEventListener('keydown', keydownHandler); firstChild.removeEventListener('keydown', keydownHandler);
firstChild.removeEventListener('focusin', focusHandler);
} }
} }

View file

@ -213,6 +213,17 @@ describe('<lion-accordion>', () => {
el.focusedIndex = 1; el.focusedIndex = 1;
expect(spy).to.have.been.calledOnce; expect(spy).to.have.been.calledOnce;
}); });
it('tabbing sets the focusedIndex correctly', async () => {
const el = /** @type {LionAccordion} */ (await fixture(basicAccordion));
const invokers = getInvokers(el);
el.focusedIndex = 0;
expect(el.focusedIndex).to.equal(0);
invokers[2].firstElementChild?.dispatchEvent(new Event('focusin'));
expect(el.focusedIndex).to.equal(2);
invokers[1].firstElementChild?.dispatchEvent(new Event('focusin'));
expect(el.focusedIndex).to.equal(1);
});
}); });
describe('Accordion Contents (slot=content)', () => { describe('Accordion Contents (slot=content)', () => {