fix(combobox): submit form on [Enter] (#2005)
fix(combobox): submit form on [Enter]
This commit is contained in:
parent
ccc762d876
commit
dbc3fc2db6
5 changed files with 94 additions and 4 deletions
5
.changeset/spotty-pumpkins-matter.md
Normal file
5
.changeset/spotty-pumpkins-matter.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'@lion/ui': patch
|
||||
---
|
||||
|
||||
[combobox] submits form on [Enter]
|
||||
|
|
@ -406,7 +406,6 @@ export class LionCombobox extends LocalizeMixin(OverlayMixin(LionListbox)) {
|
|||
* @protected
|
||||
*/
|
||||
this._ariaVersion = browserDetection.isChromium ? '1.1' : '1.0';
|
||||
|
||||
/**
|
||||
* @configure ListboxMixin
|
||||
* @protected
|
||||
|
|
@ -1072,6 +1071,9 @@ export class LionCombobox extends LocalizeMixin(OverlayMixin(LionListbox)) {
|
|||
this._setTextboxValue('');
|
||||
break;
|
||||
case 'Enter':
|
||||
if (this.multipleChoice && this.opened) {
|
||||
ev.preventDefault();
|
||||
}
|
||||
if (!this.formElements[this.activeIndex]) {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import '@lion/ui/define/lion-listbox.js';
|
|||
import '@lion/ui/define/lion-option.js';
|
||||
import { Required, Unparseable } from '@lion/ui/form-core.js';
|
||||
import { defineCE, expect, fixture, html, unsafeStatic } from '@open-wc/testing';
|
||||
import { sendKeys } from '@web/test-runner-commands';
|
||||
import { LitElement } from 'lit';
|
||||
import sinon from 'sinon';
|
||||
|
||||
|
|
@ -2678,6 +2679,57 @@ describe('lion-combobox', () => {
|
|||
mimicKeyPress(visibleOptions[1], 'Enter');
|
||||
expect(el.opened).to.equal(true);
|
||||
});
|
||||
|
||||
it('submits form on [Enter] when listbox is closed', async () => {
|
||||
const submitSpy = sinon.spy(e => e.preventDefault());
|
||||
const el = /** @type {HTMLFormElement} */ (
|
||||
await fixture(html`
|
||||
<form @submit=${submitSpy}>
|
||||
<lion-combobox name="foo" multiple-choice>
|
||||
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
||||
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
||||
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
||||
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
||||
</lion-combobox>
|
||||
<button type="submit">submit</button>
|
||||
</form>
|
||||
`)
|
||||
);
|
||||
const combobox = /** @type {LionCombobox} */ (el.querySelector('[name="foo"]'));
|
||||
const { _inputNode } = getComboboxMembers(combobox);
|
||||
await combobox.updateComplete;
|
||||
_inputNode.focus();
|
||||
await sendKeys({
|
||||
press: 'Enter',
|
||||
});
|
||||
expect(submitSpy.callCount).to.equal(1);
|
||||
});
|
||||
|
||||
it('does not submit form on [Enter] when listbox is opened', async () => {
|
||||
const submitSpy = sinon.spy(e => e.preventDefault());
|
||||
const el = /** @type {HTMLFormElement} */ (
|
||||
await fixture(html`
|
||||
<form @submit=${submitSpy}>
|
||||
<lion-combobox name="foo" multiple-choice>
|
||||
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
||||
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
||||
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
||||
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
||||
</lion-combobox>
|
||||
<button type="submit">submit</button>
|
||||
</form>
|
||||
`)
|
||||
);
|
||||
const combobox = /** @type {LionCombobox} */ (el.querySelector('[name="foo"]'));
|
||||
const { _inputNode } = getComboboxMembers(combobox);
|
||||
combobox.opened = true;
|
||||
await combobox.updateComplete;
|
||||
_inputNode.focus();
|
||||
await sendKeys({
|
||||
press: 'Enter',
|
||||
});
|
||||
expect(submitSpy.callCount).to.equal(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Match Mode', () => {
|
||||
|
|
|
|||
|
|
@ -294,7 +294,6 @@ const ListboxMixinImplementation = superclass =>
|
|||
* @protected
|
||||
*/
|
||||
this._repropagationRole = 'choice-group'; // configures FormControlMixin
|
||||
|
||||
/**
|
||||
* When listbox is coupled to a textbox (in case we are dealing with a combobox),
|
||||
* spaces should not select an element (they need to be put in the textbox)
|
||||
|
|
@ -612,7 +611,9 @@ const ListboxMixinImplementation = superclass =>
|
|||
if (key === ' ' && this._listboxReceivesNoFocus) {
|
||||
return;
|
||||
}
|
||||
if (key === ' ') {
|
||||
ev.preventDefault();
|
||||
}
|
||||
if (!this.formElements[this.activeIndex]) {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import {
|
|||
nextFrame,
|
||||
unsafeStatic,
|
||||
} from '@open-wc/testing';
|
||||
import { sendKeys } from '@web/test-runner-commands';
|
||||
import sinon from 'sinon';
|
||||
import { getListboxMembers } from '../../../exports/listbox-test-helpers.js';
|
||||
|
||||
|
|
@ -673,12 +674,41 @@ export function runListboxMixinSuite(customConfig = {}) {
|
|||
mimicKeyPress(_listboxNode, 'Enter');
|
||||
expect(options[1].checked).to.be.true;
|
||||
});
|
||||
|
||||
it('submits form on [Enter] when inputNode is an instance of HTMLInputNode', async () => {
|
||||
const submitSpy = sinon.spy(e => e.preventDefault());
|
||||
const el = /** @type {HTMLFormElement} */ (
|
||||
await _fixture(html`
|
||||
<form @submit=${submitSpy}>
|
||||
<${tag} name="foo">
|
||||
<${optionTag} .choiceValue="${'Artichoke'}">Artichoke</${optionTag}>
|
||||
<${optionTag} .choiceValue="${'Bla'}">Bla</${optionTag}>
|
||||
<${optionTag} .choiceValue="${'Chard'}">Chard</${optionTag}>
|
||||
</${tag}>
|
||||
<button type="submit">submit</button>
|
||||
</form>
|
||||
`)
|
||||
);
|
||||
const listbox = /** @type {LionListbox} */ (el.querySelector('[name="foo"]'));
|
||||
const { _inputNode } = getListboxMembers(listbox);
|
||||
if (!(_inputNode instanceof HTMLInputElement)) {
|
||||
return;
|
||||
}
|
||||
await listbox.updateComplete;
|
||||
// @ts-ignore allow protected members in tests
|
||||
|
||||
_inputNode.focus();
|
||||
await sendKeys({
|
||||
press: 'Enter',
|
||||
});
|
||||
expect(submitSpy.callCount).to.equal(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Space', () => {
|
||||
it('selects active option when "_listboxReceivesNoFocus" is true', async () => {
|
||||
// When listbox is not focusable (in case of a combobox), the user should be allowed
|
||||
// to enter a space in the focusable element (texbox)
|
||||
// to enter a space in the focusable element (textbox)
|
||||
const el = /** @type {LionListbox} */ (
|
||||
await fixture(html`
|
||||
<${tag} opened name="foo" ._listboxReceivesNoFocus="${false}" autocomplete="none" show-all-on-empty>
|
||||
|
|
|
|||
Loading…
Reference in a new issue