fix(listbox): become active on click

This commit is contained in:
Mathieu Puech 2020-12-02 00:43:12 -05:00
parent 55fd115e47
commit e808df7a99
5 changed files with 33 additions and 5 deletions

View file

@ -131,7 +131,7 @@ See [wai aria spec](https://www.w3.org/TR/wai-aria-practices/#kbd_selection_foll
export const selectionFollowsFocus = () => html` export const selectionFollowsFocus = () => html`
<lion-listbox name="combo" label="Selection follows focus" selection-follows-focus> <lion-listbox name="combo" label="Selection follows focus" selection-follows-focus>
<lion-option .choiceValue=${'Apple'}>Apple</lion-option> <lion-option .choiceValue=${'Apple'}>Apple</lion-option>
<lion-option .choiceValue=${'Artichoke'}>Artichoke</lion-option> <lion-option .choiceValue=${'Artichoke'} disabled>Artichoke</lion-option>
<lion-option .choiceValue=${'Asparagus'}>Asparagus</lion-option> <lion-option .choiceValue=${'Asparagus'}>Asparagus</lion-option>
<lion-option .choiceValue=${'Banana'}>Banana</lion-option> <lion-option .choiceValue=${'Banana'}>Banana</lion-option>
<lion-option .choiceValue=${'Beets'}>Beets</lion-option> <lion-option .choiceValue=${'Beets'}>Beets</lion-option>

View file

@ -125,8 +125,10 @@ export class LionOption extends DisabledMixin(ChoiceInputMixin(FormRegisteringMi
const parentForm = /** @type {unknown} */ (this.__parentFormGroup); const parentForm = /** @type {unknown} */ (this.__parentFormGroup);
if (parentForm && /** @type {ChoiceGroupHost} */ (parentForm).multipleChoice) { if (parentForm && /** @type {ChoiceGroupHost} */ (parentForm).multipleChoice) {
this.checked = !this.checked; this.checked = !this.checked;
this.active = !this.active;
} else { } else {
this.checked = true; this.checked = true;
this.active = true;
} }
} }
} }

View file

@ -362,7 +362,9 @@ const ListboxMixinImplementation = superclass =>
this._uncheckChildren(); this._uncheckChildren();
} }
if (this.formElements[index]) { if (this.formElements[index]) {
if (this.multipleChoice) { if (this.formElements[index].disabled) {
this._uncheckChildren();
} else if (this.multipleChoice) {
this.formElements[index].checked = !this.formElements[index].checked; this.formElements[index].checked = !this.formElements[index].checked;
} else { } else {
this.formElements[index].checked = true; this.formElements[index].checked = true;

View file

@ -912,7 +912,7 @@ export function runListboxMixinSuite(customConfig = {}) {
}); });
} }
const el = /** @type {LionListbox} */ (await fixture(html` const el = /** @type {LionListbox} */ (await fixture(html`
<${tag} opened selection-follows-focus orientation="horizontal" autocomplete="none"> <${tag} opened selection-follows-focus autocomplete="none">
<${optionTag} .choiceValue=${10}>Item 1</${optionTag}> <${optionTag} .choiceValue=${10}>Item 1</${optionTag}>
<${optionTag} .choiceValue=${20}>Item 2</${optionTag}> <${optionTag} .choiceValue=${20}>Item 2</${optionTag}>
<${optionTag} .choiceValue=${30}>Item 3</${optionTag}> <${optionTag} .choiceValue=${30}>Item 3</${optionTag}>
@ -951,7 +951,7 @@ export function runListboxMixinSuite(customConfig = {}) {
}); });
} }
const el = /** @type {LionListbox} */ (await fixture(html` const el = /** @type {LionListbox} */ (await fixture(html`
<${tag} opened selection-follows-focus autocomplete="none"> <${tag} opened selection-follows-focus orientation="horizontal" autocomplete="none">
<${optionTag} .choiceValue=${10}>Item 1</${optionTag}> <${optionTag} .choiceValue=${10}>Item 1</${optionTag}>
<${optionTag} .choiceValue=${20}>Item 2</${optionTag}> <${optionTag} .choiceValue=${20}>Item 2</${optionTag}>
<${optionTag} .choiceValue=${30}>Item 3</${optionTag}> <${optionTag} .choiceValue=${30}>Item 3</${optionTag}>
@ -1075,6 +1075,28 @@ export function runListboxMixinSuite(customConfig = {}) {
// Checked index stays where it was // Checked index stays where it was
expect(el.checkedIndex).to.equal(0); expect(el.checkedIndex).to.equal(0);
}); });
it('does not check disabled options when selection-follow-focus is enabled', async () => {
const el = await fixture(html`
<${tag} opened autocomplete="inline" .selectionFollowsFocus="${true}">
<${optionTag} .choiceValue=${'Item 1'} checked>Item 1</${optionTag}>
<${optionTag} .choiceValue=${'Item 2'} disabled>Item 2</${optionTag}>
<${optionTag} .choiceValue=${'Item 3'}>Item 3</${optionTag}>
</${tag}>
`);
const { listbox } = getProtectedMembers(el);
// Normalize activeIndex across multiple implementers of ListboxMixinSuite
el.activeIndex = 0;
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }));
expect(el.activeIndex).to.equal(1);
expect(el.checkedIndex).to.equal(-1);
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }));
expect(el.activeIndex).to.equal(2);
expect(el.checkedIndex).to.equal(2);
});
}); });
describe('Programmatic interaction', () => { describe('Programmatic interaction', () => {

View file

@ -86,14 +86,16 @@ describe('lion-option', () => {
expect(el.hasAttribute('active')).to.be.false; expect(el.hasAttribute('active')).to.be.false;
}); });
it('does become checked on [click]', async () => { it('does become checked and active on [click]', async () => {
const el = /** @type {LionOption} */ (await fixture( const el = /** @type {LionOption} */ (await fixture(
html`<lion-option .choiceValue=${10}></lion-option>`, html`<lion-option .choiceValue=${10}></lion-option>`,
)); ));
expect(el.checked).to.be.false; expect(el.checked).to.be.false;
expect(el.active).to.be.false;
el.click(); el.click();
await el.updateComplete; await el.updateComplete;
expect(el.checked).to.be.true; expect(el.checked).to.be.true;
expect(el.active).to.be.true;
}); });
it('fires active-changed event', async () => { it('fires active-changed event', async () => {