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.__createTypeAbsenceValidators();
|
||||||
|
|
||||||
this._checkForOutsideClick = this._checkForOutsideClick.bind(this);
|
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() {
|
connectedCallback() {
|
||||||
// eslint-disable-next-line wc/guard-super-call
|
super.connectedCallback(); // eslint-disable-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);
|
|
||||||
|
|
||||||
this._setRole();
|
this._setRole();
|
||||||
document.addEventListener('click', this._checkForOutsideClick);
|
|
||||||
}
|
|
||||||
|
|
||||||
_checkForOutsideClick(event) {
|
|
||||||
const outsideGroupClicked = !this.contains(event.target);
|
|
||||||
if (outsideGroupClicked) {
|
|
||||||
this.touched = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnectedCallback() {
|
disconnectedCallback() {
|
||||||
// eslint-disable-next-line wc/guard-super-call
|
super.disconnectedCallback(); // eslint-disable-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);
|
|
||||||
|
|
||||||
document.removeEventListener('click', this._checkForOutsideClick);
|
if (this.__hasActiveOutsideClickHandling) {
|
||||||
|
document.removeEventListener('click', this._checkForOutsideClick);
|
||||||
|
this.__hasActiveOutsideClickHandling = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updated(changedProps) {
|
updated(changedProps) {
|
||||||
|
|
@ -162,6 +149,23 @@ export class LionFieldset extends FormRegistrarMixin(
|
||||||
if (changedProps.has('focused')) {
|
if (changedProps.has('focused')) {
|
||||||
/** @deprecated use touched attribute instead */
|
/** @deprecated use touched attribute instead */
|
||||||
this.classList[this.focused ? 'add' : 'remove']('state-focused');
|
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>
|
</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', () => {
|
.add('Validation', () => {
|
||||||
function isFakeValidator() {
|
function isDemoValidator() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fakeValidator = (...factoryParams) => [
|
const demoValidator = (...factoryParams) => [
|
||||||
(...params) => ({ validator: isFakeValidator(...params) }),
|
(...params) => ({ validator: isDemoValidator(...params) }),
|
||||||
...factoryParams,
|
...factoryParams,
|
||||||
];
|
];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
localize.addData('en-GB', 'lion-validate+validator', {
|
localize.addData('en-GB', 'lion-validate+validator', {
|
||||||
error: {
|
error: {
|
||||||
validator: 'Fake error message',
|
validator: 'Demo error message',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
@ -137,7 +105,7 @@ storiesOf('Forms|Fieldset', module)
|
||||||
}
|
}
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<lion-fieldset id="someId" .errorValidators=${[fakeValidator()]}>
|
<lion-fieldset id="someId" .errorValidators=${[demoValidator()]}>
|
||||||
<lion-input name="input1" label="Label"></lion-input>
|
<lion-input name="input1" label="Label"></lion-input>
|
||||||
<button
|
<button
|
||||||
@click=${() => {
|
@click=${() => {
|
||||||
|
|
@ -154,4 +122,90 @@ storiesOf('Forms|Fieldset', module)
|
||||||
Tab-able
|
Tab-able
|
||||||
</button>
|
</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}>
|
<${childTag} name="input2"></${childTag}>
|
||||||
</${tag}>
|
</${tag}>
|
||||||
`);
|
`);
|
||||||
|
const el2 = await fixture(html`
|
||||||
|
<${tag}>
|
||||||
|
<${childTag} name="input1"></${childTag}>
|
||||||
|
<${childTag} name="input2"></${childTag}>
|
||||||
|
</${tag}>
|
||||||
|
`);
|
||||||
|
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
const outside = await fixture(html`
|
const outside = await fixture(html`
|
||||||
<button>outside</button>
|
<button>outside</button>
|
||||||
`);
|
`);
|
||||||
|
|
||||||
|
outside.click();
|
||||||
|
expect(el.touched, 'unfocused fieldset should stays untouched').to.be.false;
|
||||||
|
|
||||||
el.children[1].focus();
|
el.children[1].focus();
|
||||||
el.children[2].focus();
|
el.children[2].focus();
|
||||||
expect(el.touched).to.be.false;
|
expect(el.touched).to.be.false;
|
||||||
|
|
||||||
outside.click(); // blur the group via a click
|
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(el.touched).to.be.true;
|
||||||
|
|
||||||
|
expect(el2.touched).to.be.false;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('potentially shows fieldset error message on interaction change', async () => {
|
it('potentially shows fieldset error message on interaction change', async () => {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue