fix(form-core): order aria-labelledby and aria-describedby based on slot order instead of dom order
This commit is contained in:
parent
5073ea4760
commit
659cbff18c
3 changed files with 53 additions and 32 deletions
5
.changeset/witty-houses-argue.md
Normal file
5
.changeset/witty-houses-argue.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'@lion/ui': patch
|
||||
---
|
||||
|
||||
[form-core] order aria-labelledby and aria-describedby based on slot order instead of dom order
|
||||
|
|
@ -390,8 +390,20 @@ const FormControlMixinImplementation = superclass =>
|
|||
const insideNodes = nodes.filter(n => this.contains(n));
|
||||
const outsideNodes = nodes.filter(n => !this.contains(n));
|
||||
|
||||
const insideSlots = insideNodes.map(n => n.assignedSlot || n);
|
||||
const orderedInsideSlots = [...getAriaElementsInRightDomOrder(insideSlots)];
|
||||
/** @type {Element[]} */
|
||||
const orderedInsideNodes = [];
|
||||
orderedInsideSlots.forEach(assignedNode => {
|
||||
insideNodes.forEach(node => {
|
||||
// @ts-ignore
|
||||
if (assignedNode.name === node.slot) {
|
||||
orderedInsideNodes.push(node);
|
||||
}
|
||||
});
|
||||
});
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
nodes = [...getAriaElementsInRightDomOrder(insideNodes), ...outsideNodes];
|
||||
nodes = [...orderedInsideNodes, ...outsideNodes];
|
||||
}
|
||||
const string = nodes.map(n => n.id).join(' ');
|
||||
this._inputNode.setAttribute(attrName, string);
|
||||
|
|
|
|||
|
|
@ -349,7 +349,7 @@ describe('FormControlMixin', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('sorts internal elements, and allows opt-out', async () => {
|
||||
it('sorts internal elements based on assigned slots, and allows opt-out', async () => {
|
||||
const wrapper = await fixture(html`
|
||||
<div id="wrapper">
|
||||
<${tag}>
|
||||
|
|
@ -359,9 +359,8 @@ describe('FormControlMixin', () => {
|
|||
Added to description by default
|
||||
</div>
|
||||
</${tag}>
|
||||
<div id="externalLabelB">should go after input internals</div>
|
||||
<div id="externalDescriptionB">should go after input internals</div>
|
||||
</div>`);
|
||||
</div>
|
||||
`);
|
||||
const el = /** @type {FormControlMixinClass} */ (wrapper.querySelector(tagString));
|
||||
const { _inputNode } = getFormControlMembers(el);
|
||||
|
||||
|
|
@ -370,36 +369,41 @@ describe('FormControlMixin', () => {
|
|||
// A real life scenario would be for instance when
|
||||
// a Field or FormGroup would be extended and an extra slot would be added in the template
|
||||
const myInput = /** @type {HTMLElement} */ (wrapper.querySelector('#myInput'));
|
||||
const internalLabel = /** @type {HTMLElement} */ (wrapper.querySelector('#internalLabel'));
|
||||
const internalDescription = /** @type {HTMLElement} */ (
|
||||
wrapper.querySelector('#internalDescription')
|
||||
);
|
||||
|
||||
el.addToAriaLabelledBy(myInput);
|
||||
await el.updateComplete;
|
||||
el.addToAriaDescribedBy(myInput);
|
||||
await el.updateComplete;
|
||||
|
||||
expect(
|
||||
/** @type {string} */ (_inputNode.getAttribute('aria-labelledby')).split(' '),
|
||||
).to.eql(['myInput', 'internalLabel']);
|
||||
expect(
|
||||
/** @type {string} */ (_inputNode.getAttribute('aria-describedby')).split(' '),
|
||||
).to.eql(['myInput', 'internalDescription']);
|
||||
|
||||
// cleanup
|
||||
el.removeFromAriaLabelledBy(myInput);
|
||||
await el.updateComplete;
|
||||
el.removeFromAriaDescribedBy(myInput);
|
||||
await el.updateComplete;
|
||||
|
||||
// opt-out of reorder
|
||||
el.addToAriaLabelledBy(myInput, { reorder: false });
|
||||
await el.updateComplete;
|
||||
el.addToAriaDescribedBy(myInput, { reorder: false });
|
||||
await el.updateComplete;
|
||||
|
||||
expect(
|
||||
/** @type {string} */ (_inputNode.getAttribute('aria-labelledby')).split(' '),
|
||||
).to.eql(['internalLabel', 'myInput']);
|
||||
expect(
|
||||
/** @type {string} */ (_inputNode.getAttribute('aria-describedby')).split(' '),
|
||||
).to.eql(['internalDescription', 'myInput']);
|
||||
|
||||
// cleanup
|
||||
el.removeFromAriaLabelledBy(internalLabel);
|
||||
await el.updateComplete;
|
||||
el.removeFromAriaDescribedBy(internalDescription);
|
||||
await el.updateComplete;
|
||||
|
||||
// opt-out of reorder
|
||||
el.addToAriaLabelledBy(internalLabel, { reorder: false });
|
||||
await el.updateComplete;
|
||||
el.addToAriaDescribedBy(internalDescription, { reorder: false });
|
||||
await el.updateComplete;
|
||||
|
||||
expect(
|
||||
/** @type {string} */ (_inputNode.getAttribute('aria-labelledby')).split(' '),
|
||||
).to.eql(['myInput', 'internalLabel']);
|
||||
expect(
|
||||
/** @type {string} */ (_inputNode.getAttribute('aria-describedby')).split(' '),
|
||||
).to.eql(['myInput', 'internalDescription']);
|
||||
});
|
||||
|
||||
it('respects provided order for external elements', async () => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue