fix(form-core): add focusableNode to choiceGroupMixin to make _setFo… (#2382)
* fix(form-core): add focusableNode to choiceGroupMixin to make \_setFocusOnFirstErroneousFormElement function work for checkbox-group and radio-group * chore: rewrite check for _setFocusOnFirstErroneousFormElement to make it work without focusableNode inside LionChoiceGroup
This commit is contained in:
parent
905ed37823
commit
2d4fb0ecdb
3 changed files with 96 additions and 13 deletions
5
.changeset/funny-carrots-laugh.md
Normal file
5
.changeset/funny-carrots-laugh.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'@lion/ui': patch
|
||||
---
|
||||
|
||||
[form-core] make \_setFocusOnFirstErroneousFormElement work for checkbox-group, radio-group and nested fieldsets
|
||||
|
|
@ -10,15 +10,6 @@ const throwFormNodeError = () => {
|
|||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {FormRegistrarHost} formEl
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasFocusableChildren(formEl) {
|
||||
// this implies all children have the same type (either all of them are focusable or none of them are)
|
||||
return formEl.formElements?.some(child => child._focusableNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* LionForm: form wrapper providing extra features and integration with lion-field elements.
|
||||
*
|
||||
|
|
@ -104,10 +95,10 @@ export class LionForm extends LionFieldset {
|
|||
element.formElements.find(child => child.hasFeedbackFor.includes('error')) ||
|
||||
element.formElements[0];
|
||||
|
||||
if (hasFocusableChildren(firstFormElWithError)) {
|
||||
this._setFocusOnFirstErroneousFormElement(firstFormElWithError);
|
||||
} else {
|
||||
if (firstFormElWithError._focusableNode) {
|
||||
firstFormElWithError._focusableNode.focus();
|
||||
} else {
|
||||
this._setFocusOnFirstErroneousFormElement(firstFormElWithError);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,10 @@ import '@lion/ui/define/lion-field.js';
|
|||
import '@lion/ui/define/lion-validation-feedback.js';
|
||||
import '@lion/ui/define/lion-listbox.js';
|
||||
import '@lion/ui/define/lion-option.js';
|
||||
import '@lion/ui/define/lion-checkbox-group.js';
|
||||
import '@lion/ui/define/lion-checkbox.js';
|
||||
import '@lion/ui/define/lion-radio-group.js';
|
||||
import '@lion/ui/define/lion-radio.js';
|
||||
import '@lion/ui/define/lion-form.js';
|
||||
import {
|
||||
aTimeout,
|
||||
|
|
@ -264,10 +268,31 @@ describe('<lion-form>', () => {
|
|||
button.click();
|
||||
expect(dispatchSpy.args[0][0].type).to.equal('submit');
|
||||
const fieldset = el.formElements[0];
|
||||
// @ts-ignore [allow-protected] in test
|
||||
expect(document.activeElement).to.equal(fieldset.formElements[0]._inputNode);
|
||||
});
|
||||
|
||||
it('sets focus on submit to the first form element within a erroneous fieldset within another fieldset', async () => {
|
||||
const el = await fixture(html`
|
||||
<lion-form>
|
||||
<form>
|
||||
<lion-fieldset name="parentFieldset">
|
||||
<lion-fieldset name="childFieldset" .validators="${[new Required()]}">
|
||||
<${childTag} name="firstName"></${childTag}>
|
||||
</lion-fieldset>
|
||||
</lion-fieldset>
|
||||
|
||||
<button type="submit">submit</button>
|
||||
</form>
|
||||
</lion-form>
|
||||
`);
|
||||
const button = /** @type {HTMLButtonElement} */ (el.querySelector('button'));
|
||||
const parentFieldSetEl = el.formElements[0];
|
||||
const childFieldsetEl = parentFieldSetEl.formElements[0];
|
||||
const inputEl = childFieldsetEl.formElements[0];
|
||||
button.click();
|
||||
expect(document.activeElement).to.equal(inputEl._focusableNode);
|
||||
});
|
||||
|
||||
it('sets focus on submit to the first form element within a erroneous listbox', async () => {
|
||||
const el = await fixture(html`
|
||||
<lion-form>
|
||||
|
|
@ -285,4 +310,66 @@ describe('<lion-form>', () => {
|
|||
const listboxEl = el.formElements[0];
|
||||
expect(document.activeElement).to.equal(listboxEl._inputNode);
|
||||
});
|
||||
|
||||
it('sets focus on submit to the first form element within a erroneous listbox within a fieldset', async () => {
|
||||
const el = await fixture(html`
|
||||
<lion-form>
|
||||
<form>
|
||||
<lion-fieldset name="fieldset">
|
||||
<lion-listbox name="name" .validators="${[new Required()]}">
|
||||
<lion-option value="a">a</lion-option>
|
||||
<lion-option value="b">b</lion-option>
|
||||
</lion-listbox>
|
||||
</lion-fieldset>
|
||||
<button type="submit">submit</button>
|
||||
</form>
|
||||
</lion-form>
|
||||
`);
|
||||
const button = /** @type {HTMLButtonElement} */ (el.querySelector('button'));
|
||||
button.click();
|
||||
const fieldsetEl = el.formElements[0];
|
||||
const listboxEl = fieldsetEl.formElements[0];
|
||||
expect(document.activeElement).to.equal(listboxEl._inputNode);
|
||||
});
|
||||
|
||||
it('sets focus on submit to the first form element within a erroneous checkbox-group', async () => {
|
||||
const el = await fixture(html`
|
||||
<lion-form>
|
||||
<form>
|
||||
<lion-checkbox-group name="name" .validators="${[new Required()]}">
|
||||
<lion-checkbox .choiceValue=${'a'} label="a"></lion-checkbox>
|
||||
<lion-checkbox .choiceValue=${'b'} label="b"></lion-checkbox>
|
||||
</lion-checkbox-group>
|
||||
<button type="submit">submit</button>
|
||||
</form>
|
||||
</lion-form>
|
||||
`);
|
||||
const button = /** @type {HTMLButtonElement} */ (el.querySelector('button'));
|
||||
const checkboxGroupEl = el.formElements[0];
|
||||
const checkboxEl = checkboxGroupEl.formElements[0];
|
||||
button.click();
|
||||
expect(document.activeElement).to.equal(checkboxEl._focusableNode);
|
||||
});
|
||||
|
||||
it('sets focus on submit to the first form element within a erroneous radio-group', async () => {
|
||||
const el = await fixture(html`
|
||||
<lion-form>
|
||||
<form>
|
||||
<lion-radio-group name="name" .validators="${[new Required()]}">
|
||||
<lion-radio .choiceValue=${'a'} label="a"></lion-radio>
|
||||
<lion-radio .choiceValue=${'b'} label="b"></lion-radio>
|
||||
</lion-radio-group>
|
||||
</lion-fieldset>
|
||||
|
||||
<button type="submit">submit</button>
|
||||
</form>
|
||||
</lion-form>
|
||||
`);
|
||||
const button = /** @type {HTMLButtonElement} */ (el.querySelector('button'));
|
||||
|
||||
const radioGroupEl = el.formElements[0];
|
||||
const radioEl = radioGroupEl.formElements[0];
|
||||
button.click();
|
||||
expect(document.activeElement).to.equal(radioEl._focusableNode);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue