fix(fieldset): outside click only effects focused groups
This commit is contained in:
parent
c984a66d4b
commit
378e940ece
3 changed files with 132 additions and 61 deletions
|
|
@ -101,38 +101,25 @@ export class LionFieldset extends FormRegistrarMixin(
|
|||
this.__createTypeAbsenceValidators();
|
||||
|
||||
this._checkForOutsideClick = this._checkForOutsideClick.bind(this);
|
||||
|
||||
this.addEventListener('focusin', this._syncFocused);
|
||||
this.addEventListener('focusout', this._onFocusOut);
|
||||
this.addEventListener('validation-done', this.__validate);
|
||||
this.addEventListener('dirty-changed', this._syncDirty);
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
// eslint-disable-next-line wc/guard-super-call
|
||||
super.connectedCallback();
|
||||
|
||||
this.addEventListener('focusin', this._updateTouchedClass);
|
||||
this.addEventListener('focusout', this._onFocusOut);
|
||||
this.addEventListener('focusin', this._syncFocused);
|
||||
|
||||
this.addEventListener('validation-done', this.__validate);
|
||||
this.addEventListener('dirty-changed', this._syncDirty);
|
||||
|
||||
super.connectedCallback(); // eslint-disable-line wc/guard-super-call
|
||||
this._setRole();
|
||||
document.addEventListener('click', this._checkForOutsideClick);
|
||||
}
|
||||
|
||||
_checkForOutsideClick(event) {
|
||||
const outsideGroupClicked = !this.contains(event.target);
|
||||
if (outsideGroupClicked) {
|
||||
this.touched = true;
|
||||
}
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
// eslint-disable-next-line wc/guard-super-call
|
||||
super.disconnectedCallback();
|
||||
this.removeEventListener('validation-done', this.__validate);
|
||||
this.removeEventListener('touched-changed', this._updateTouched);
|
||||
this.removeEventListener('dirty-changed', this._syncDirty);
|
||||
super.disconnectedCallback(); // eslint-disable-line wc/guard-super-call
|
||||
|
||||
if (this.__hasActiveOutsideClickHandling) {
|
||||
document.removeEventListener('click', this._checkForOutsideClick);
|
||||
this.__hasActiveOutsideClickHandling = false;
|
||||
}
|
||||
}
|
||||
|
||||
updated(changedProps) {
|
||||
|
|
@ -162,6 +149,23 @@ export class LionFieldset extends FormRegistrarMixin(
|
|||
if (changedProps.has('focused')) {
|
||||
/** @deprecated use touched attribute instead */
|
||||
this.classList[this.focused ? 'add' : 'remove']('state-focused');
|
||||
if (this.focused === true) {
|
||||
this.__setupOutsideClickHandling();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__setupOutsideClickHandling() {
|
||||
if (!this.__hasActiveOutsideClickHandling) {
|
||||
document.addEventListener('click', this._checkForOutsideClick);
|
||||
this.__hasActiveOutsideClickHandling = true;
|
||||
}
|
||||
}
|
||||
|
||||
_checkForOutsideClick(event) {
|
||||
const outsideGroupClicked = !this.contains(event.target);
|
||||
if (outsideGroupClicked) {
|
||||
this.touched = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -84,52 +84,20 @@ storiesOf('Forms|Fieldset', module)
|
|||
</lion-fieldset>
|
||||
`,
|
||||
)
|
||||
.add('Validation 2 inputs', () => {
|
||||
const input1IsTen = value => ({
|
||||
input1IsTen: value.input1 === 'cats' && value.input2 === 'dogs',
|
||||
});
|
||||
localize.locale = 'en-GB';
|
||||
try {
|
||||
localize.addData('en-GB', 'lion-validate+input1IsTen', {
|
||||
error: {
|
||||
input1IsTen: 'Input 1 needs to be "cats" and Input 2 needs to be "dogs"',
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
// expected as it's a demo
|
||||
}
|
||||
|
||||
return html`
|
||||
<lion-fieldset .errorValidators=${[[input1IsTen]]}>
|
||||
<lion-input
|
||||
label="An all time YouTube favorite"
|
||||
name="input1"
|
||||
help-text="longer then 2 characters"
|
||||
.errorValidators=${[minLengthValidator(3)]}
|
||||
></lion-input>
|
||||
<lion-input
|
||||
label="Another all time YouTube favorite"
|
||||
name="input2"
|
||||
help-text="longer then 2 characters"
|
||||
.errorValidators=${[minLengthValidator(3)]}
|
||||
></lion-input>
|
||||
</lion-fieldset>
|
||||
`;
|
||||
})
|
||||
.add('Validation', () => {
|
||||
function isFakeValidator() {
|
||||
function isDemoValidator() {
|
||||
return false;
|
||||
}
|
||||
|
||||
const fakeValidator = (...factoryParams) => [
|
||||
(...params) => ({ validator: isFakeValidator(...params) }),
|
||||
const demoValidator = (...factoryParams) => [
|
||||
(...params) => ({ validator: isDemoValidator(...params) }),
|
||||
...factoryParams,
|
||||
];
|
||||
|
||||
try {
|
||||
localize.addData('en-GB', 'lion-validate+validator', {
|
||||
error: {
|
||||
validator: 'Fake error message',
|
||||
validator: 'Demo error message',
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
|
|
@ -137,7 +105,7 @@ storiesOf('Forms|Fieldset', module)
|
|||
}
|
||||
|
||||
return html`
|
||||
<lion-fieldset id="someId" .errorValidators=${[fakeValidator()]}>
|
||||
<lion-fieldset id="someId" .errorValidators=${[demoValidator()]}>
|
||||
<lion-input name="input1" label="Label"></lion-input>
|
||||
<button
|
||||
@click=${() => {
|
||||
|
|
@ -154,4 +122,90 @@ storiesOf('Forms|Fieldset', module)
|
|||
Tab-able
|
||||
</button>
|
||||
`;
|
||||
})
|
||||
.add('Validation 2 inputs', () => {
|
||||
const isCatsAndDogs = value => ({
|
||||
isCatsAndDogs: value.input1 === 'cats' && value.input2 === 'dogs',
|
||||
});
|
||||
localize.locale = 'en-GB';
|
||||
try {
|
||||
localize.addData('en-GB', 'lion-validate+isCatsAndDogs', {
|
||||
error: {
|
||||
isCatsAndDogs:
|
||||
'[Fieldset Error] Input 1 needs to be "cats" and Input 2 needs to be "dogs"',
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
// expected as it's a demo
|
||||
}
|
||||
|
||||
return html`
|
||||
<lion-fieldset .errorValidators=${[[isCatsAndDogs]]}>
|
||||
<lion-input
|
||||
label="An all time YouTube favorite"
|
||||
name="input1"
|
||||
help-text="longer then 2 characters"
|
||||
.errorValidators=${[minLengthValidator(3)]}
|
||||
></lion-input>
|
||||
<lion-input
|
||||
label="Another all time YouTube favorite"
|
||||
name="input2"
|
||||
help-text="longer then 2 characters"
|
||||
.errorValidators=${[minLengthValidator(3)]}
|
||||
></lion-input>
|
||||
</lion-fieldset>
|
||||
`;
|
||||
})
|
||||
.add('Validation 2 fieldsets', () => {
|
||||
const isCats = value => ({
|
||||
isCats: value.input1 === 'cats',
|
||||
});
|
||||
localize.locale = 'en-GB';
|
||||
try {
|
||||
localize.addData('en-GB', 'lion-validate+isCats', {
|
||||
error: {
|
||||
isCats: '[Fieldset Nr. 1 Error] Input 1 needs to be "cats"',
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
// expected as it's a demo
|
||||
}
|
||||
|
||||
const isDogs = value => ({
|
||||
isDogs: value.input1 === 'dogs',
|
||||
});
|
||||
localize.locale = 'en-GB';
|
||||
try {
|
||||
localize.addData('en-GB', 'lion-validate+isDogs', {
|
||||
error: {
|
||||
isDogs: '[Fieldset Nr. 2 Error] Input 1 needs to be "dogs"',
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
// expected as it's a demo
|
||||
}
|
||||
|
||||
return html`
|
||||
<lion-fieldset .errorValidators=${[[isCats]]}>
|
||||
<label slot="label">Fieldset Nr. 1</label>
|
||||
<lion-input
|
||||
label="An all time YouTube favorite"
|
||||
name="input1"
|
||||
help-text="longer then 2 characters"
|
||||
.errorValidators=${[minLengthValidator(3)]}
|
||||
></lion-input>
|
||||
</lion-fieldset>
|
||||
<br />
|
||||
<hr />
|
||||
<br />
|
||||
<lion-fieldset .errorValidators=${[[isDogs]]}>
|
||||
<label slot="label">Fieldset Nr. 2</label>
|
||||
<lion-input
|
||||
label="An all time YouTube favorite"
|
||||
name="input1"
|
||||
help-text="longer then 2 characters"
|
||||
.errorValidators=${[minLengthValidator(3)]}
|
||||
></lion-input>
|
||||
</lion-fieldset>
|
||||
`;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -421,17 +421,30 @@ describe('<lion-fieldset>', () => {
|
|||
<${childTag} name="input2"></${childTag}>
|
||||
</${tag}>
|
||||
`);
|
||||
const el2 = await fixture(html`
|
||||
<${tag}>
|
||||
<${childTag} name="input1"></${childTag}>
|
||||
<${childTag} name="input2"></${childTag}>
|
||||
</${tag}>
|
||||
`);
|
||||
|
||||
await nextFrame();
|
||||
const outside = await fixture(html`
|
||||
<button>outside</button>
|
||||
`);
|
||||
|
||||
outside.click();
|
||||
expect(el.touched, 'unfocused fieldset should stays untouched').to.be.false;
|
||||
|
||||
el.children[1].focus();
|
||||
el.children[2].focus();
|
||||
expect(el.touched).to.be.false;
|
||||
|
||||
outside.click(); // blur the group via a click
|
||||
outside.focus(); // a real mouse click moves focus as well
|
||||
expect(el.touched).to.be.true;
|
||||
|
||||
expect(el2.touched).to.be.false;
|
||||
});
|
||||
|
||||
it('potentially shows fieldset error message on interaction change', async () => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue