fix: - rearranging invokers and content for a correct tab order is now implemented by changing the slot attributes of both instead of moving them

- changed css for this implementation
     - fixed tests
     - added changeset
This commit is contained in:
Danny Moerkerke 2023-01-12 15:55:39 +01:00 committed by Thomas Allmer
parent af2e0293a1
commit 9fb14fa1c5
3 changed files with 56 additions and 41 deletions

View file

@ -0,0 +1,5 @@
---
'@lion/ui': patch
---
`accordion`: rearranging invokers and content for a correct tab order is now implemented by changing the slot attributes of both instead of moving them, changed css for this implementation, updated tests

View file

@ -44,21 +44,21 @@ export class LionAccordion extends LitElement {
flex-direction: column;
}
.accordion [slot='invoker'] {
.accordion ::slotted(.invoker) {
margin: 0;
}
.accordion [slot='invoker'][expanded] {
.accordion ::slotted(.invoker)[expanded] {
font-weight: bold;
}
.accordion [slot='content'] {
.accordion ::slotted(.content) {
margin: 0;
visibility: hidden;
display: none;
}
.accordion [slot='content'][expanded] {
.accordion ::slotted(.content[expanded]) {
visibility: visible;
display: block;
}
@ -159,9 +159,15 @@ export class LionAccordion extends LitElement {
* @private
*/
__setupStore() {
const accordion = this.shadowRoot?.querySelector('slot[name=_accordion]');
const existingInvokers = accordion ? accordion.querySelectorAll('[slot=invoker]') : [];
const existingContent = accordion ? accordion.querySelectorAll('[slot=content]') : [];
const accordion = /** @type {HTMLSlotElement} */ (
this.shadowRoot?.querySelector('slot[name=_accordion]')
);
const existingInvokers = accordion
? accordion.assignedElements().filter(child => child.classList.contains('invoker'))
: [];
const existingContent = accordion
? accordion.assignedElements().filter(child => child.classList.contains('content'))
: [];
const invokers = /** @type {HTMLElement[]} */ ([
...Array.from(existingInvokers),
@ -212,14 +218,21 @@ export class LionAccordion extends LitElement {
const invokers = /** @type {HTMLElement[]} */ (
Array.from(this.children).filter(child => child.slot === 'invoker')
);
const contents = /** @type {HTMLElement[]} */ (
Array.from(this.children).filter(child => child.slot === 'content')
);
const accordion = this.shadowRoot?.querySelector('slot[name=_accordion]');
if (accordion) {
invokers.forEach((invoker, index) => {
accordion.insertAdjacentElement('beforeend', invoker);
accordion.insertAdjacentElement('beforeend', contents[index]);
invoker.classList.add('invoker');
// eslint-disable-next-line no-param-reassign
invoker.slot = '_accordion';
contents[index].classList.add('content');
contents[index].slot = '_accordion';
});
}
}

View file

@ -23,27 +23,27 @@ const basicAccordion = html`
* @param {Element} el
*/
function getAccordionChildren(el) {
const slot = el.shadowRoot?.querySelector('slot[name=_accordion]');
if (el.shadowRoot) {
const slot = el.shadowRoot?.querySelector('slot[name=_accordion]');
return slot ? slot.children : [];
return slot && slot instanceof HTMLSlotElement ? slot.assignedElements() : [];
}
return [];
}
/**
* @param {Element} el
*/
function getInvokers(el) {
const slot = el.shadowRoot?.querySelector('slot[name=_accordion]');
return slot ? slot.querySelectorAll('[slot=invoker]') : [];
return getAccordionChildren(el).filter(child => child.classList.contains('invoker'));
}
/**
* @param {Element} el
*/
function getContents(el) {
const slot = el.shadowRoot?.querySelector('slot[name=_accordion]');
return slot ? slot.querySelectorAll('[slot=content]') : [];
return getAccordionChildren(el).filter(child => child.classList.contains('content'));
}
describe('<lion-accordion>', () => {
@ -68,14 +68,14 @@ describe('<lion-accordion>', () => {
expect(
Array.from(getAccordionChildren(el)).find(
child => child.slot === 'invoker' && child.hasAttribute('expanded'),
child => child.className === 'invoker' && child.hasAttribute('expanded'),
)?.textContent,
).to.equal('invoker 2');
el.expanded = [0];
expect(
Array.from(getAccordionChildren(el)).find(
child => child.slot === 'invoker' && child.hasAttribute('expanded'),
child => child.className === 'invoker' && child.hasAttribute('expanded'),
)?.textContent,
).to.equal('invoker 1');
});
@ -146,17 +146,16 @@ describe('<lion-accordion>', () => {
`)
);
expect(el.focusedIndex).to.equal(1);
expect(
Array.from(getAccordionChildren(el)).find(
child => child.slot === 'invoker' && child.firstElementChild?.hasAttribute('focused'),
)?.textContent,
Array.from(getInvokers(el)).find(child => child.firstElementChild?.hasAttribute('focused'))
?.textContent,
).to.equal('invoker 2');
el.focusedIndex = 0;
expect(
Array.from(getAccordionChildren(el)).find(
child => child.slot === 'invoker' && child.firstElementChild?.hasAttribute('focused'),
)?.textContent,
Array.from(getInvokers(el)).find(child => child.firstElementChild?.hasAttribute('focused'))
?.textContent,
).to.equal('invoker 1');
});
@ -360,14 +359,10 @@ describe('<lion-accordion>', () => {
await el.updateComplete;
expect(
Array.from(getAccordionChildren(el)).find(
child => child.slot === 'invoker' && child.hasAttribute('expanded'),
)?.textContent,
Array.from(getInvokers(el)).find(child => child.hasAttribute('expanded'))?.textContent,
).to.equal('invoker 5');
expect(
Array.from(getAccordionChildren(el)).find(
child => child.slot === 'content' && child.hasAttribute('expanded'),
)?.textContent,
Array.from(getContents(el)).find(child => child.hasAttribute('expanded'))?.textContent,
).to.equal('content 5');
});
@ -410,11 +405,13 @@ describe('<lion-accordion>', () => {
<div slot="content">content 2</div>
</lion-accordion>
`);
// console.log(getAccordionChildren(el));
expect(
Array.from(getAccordionChildren(el)).find(child => child.slot === 'content'),
Array.from(getAccordionChildren(el)).find(child => child.classList.contains('content')),
).to.not.have.attribute('tabindex');
expect(
Array.from(getAccordionChildren(el)).find(child => child.slot === 'content'),
Array.from(getAccordionChildren(el)).find(child => child.classList.contains('content')),
).to.not.have.attribute('tabindex');
});
@ -445,10 +442,10 @@ describe('<lion-accordion>', () => {
<div slot="content">content</div>
</lion-accordion>
`);
expect(
Array.from(getAccordionChildren(el)).find(child => child.slot === 'invoker')
?.firstElementChild,
).to.have.attribute('aria-expanded', 'false');
expect(Array.from(getInvokers(el))[0]?.firstElementChild).to.have.attribute(
'aria-expanded',
'false',
);
});
it('adds aria-expanded="true" to invoker when its content is expanded', async () => {
@ -461,10 +458,10 @@ describe('<lion-accordion>', () => {
`)
);
el.expanded = [0];
expect(
Array.from(getAccordionChildren(el)).find(child => child.slot === 'invoker')
?.firstElementChild,
).to.have.attribute('aria-expanded', 'true');
expect(Array.from(getInvokers(el))[0]?.firstElementChild).to.have.attribute(
'aria-expanded',
'true',
);
});
});