mirror of
https://github.com/shoelace-style/webawesome.git
synced 2026-01-12 04:09:12 +00:00
validate even with novalidate; fixes #1164
This commit is contained in:
@@ -15,6 +15,7 @@ New versions of Shoelace are released as-needed and generally occur when a criti
|
||||
- Fixed a bug in the template for `<sl-select>` that caused the `form-control-help-text` part to not be in the same location as other form controls [#1178](https://github.com/shoelace-style/shoelace/issues/1178)
|
||||
- Fixed a bug in `<sl-checkbox>` and `<sl-switch>` that caused the browser to scroll incorrectly when focusing on a control in a container with overflow [#1169](https://github.com/shoelace-style/shoelace/issues/1169)
|
||||
- Fixed a bug in `<sl-menu-item>` that caused the `click` event to be emitted when the item was disabled [#1113](https://github.com/shoelace-style/shoelace/issues/1113)
|
||||
- Fixed a bug in form controls that erroneously prevented validation states from being set when `novalidate` was used on the containing form [#1164](https://github.com/shoelace-style/shoelace/issues/1164)
|
||||
- Improved the behavior of `<sl-dropdown>` in Safari so keyboard interaction works the same as in other browsers [#1177](https://github.com/shoelace-style/shoelace/issues/1177)
|
||||
- Improved the [icons](/components/icon) page so it's not as sluggish in Safari [#1122](https://github.com/shoelace-style/shoelace/issues/1122)
|
||||
|
||||
|
||||
@@ -199,6 +199,18 @@ describe('<sl-checkbox>', () => {
|
||||
|
||||
expect(formData.get('a')).to.equal('1');
|
||||
});
|
||||
|
||||
it('should receive validation attributes ("states") even when novalidate is used on the parent form', async () => {
|
||||
const el = await fixture<HTMLFormElement>(html` <form novalidate><sl-checkbox required></sl-checkbox></form> `);
|
||||
const checkbox = el.querySelector<SlCheckbox>('sl-checkbox')!;
|
||||
|
||||
expect(checkbox.hasAttribute('data-required')).to.be.true;
|
||||
expect(checkbox.hasAttribute('data-optional')).to.be.false;
|
||||
expect(checkbox.hasAttribute('data-invalid')).to.be.true;
|
||||
expect(checkbox.hasAttribute('data-valid')).to.be.false;
|
||||
expect(checkbox.hasAttribute('data-user-invalid')).to.be.false;
|
||||
expect(checkbox.hasAttribute('data-user-valid')).to.be.false;
|
||||
});
|
||||
});
|
||||
|
||||
describe('when resetting a form', () => {
|
||||
|
||||
@@ -155,6 +155,18 @@ describe('<sl-input>', () => {
|
||||
expect(el.hasAttribute('data-user-invalid')).to.be.true;
|
||||
expect(el.hasAttribute('data-user-valid')).to.be.false;
|
||||
});
|
||||
|
||||
it('should receive validation attributes ("states") even when novalidate is used on the parent form', async () => {
|
||||
const el = await fixture<HTMLFormElement>(html` <form novalidate><sl-input required></sl-input></form> `);
|
||||
const input = el.querySelector<SlInput>('sl-input')!;
|
||||
|
||||
expect(input.hasAttribute('data-required')).to.be.true;
|
||||
expect(input.hasAttribute('data-optional')).to.be.false;
|
||||
expect(input.hasAttribute('data-invalid')).to.be.true;
|
||||
expect(input.hasAttribute('data-valid')).to.be.false;
|
||||
expect(input.hasAttribute('data-user-invalid')).to.be.false;
|
||||
expect(input.hasAttribute('data-user-valid')).to.be.false;
|
||||
});
|
||||
});
|
||||
|
||||
describe('when submitting a form', () => {
|
||||
|
||||
@@ -130,6 +130,25 @@ describe('<sl-radio-group>', () => {
|
||||
expect(radioGroup.hasAttribute('data-user-invalid')).to.be.true;
|
||||
expect(radioGroup.hasAttribute('data-user-valid')).to.be.false;
|
||||
});
|
||||
|
||||
it('should receive validation attributes ("states") even when novalidate is used on the parent form', async () => {
|
||||
const el = await fixture<HTMLFormElement>(html`
|
||||
<form novalidate>
|
||||
<sl-radio-group required>
|
||||
<sl-radio value="1"></sl-radio>
|
||||
<sl-radio value="2"></sl-radio>
|
||||
</sl-radio-group>
|
||||
</form>
|
||||
`);
|
||||
const radioGroup = el.querySelector<SlRadioGroup>('sl-radio-group')!;
|
||||
|
||||
expect(radioGroup.hasAttribute('data-required')).to.be.true;
|
||||
expect(radioGroup.hasAttribute('data-optional')).to.be.false;
|
||||
expect(radioGroup.hasAttribute('data-invalid')).to.be.true;
|
||||
expect(radioGroup.hasAttribute('data-valid')).to.be.false;
|
||||
expect(radioGroup.hasAttribute('data-user-invalid')).to.be.false;
|
||||
expect(radioGroup.hasAttribute('data-user-valid')).to.be.false;
|
||||
});
|
||||
});
|
||||
|
||||
it('should show a constraint validation error when setCustomValidity() is called', async () => {
|
||||
|
||||
@@ -169,6 +169,19 @@ describe('<sl-range>', () => {
|
||||
expect(range.hasAttribute('data-user-valid')).to.be.false;
|
||||
});
|
||||
|
||||
it('should receive validation attributes ("states") even when novalidate is used on the parent form', async () => {
|
||||
const el = await fixture<HTMLFormElement>(html` <form novalidate><sl-range></sl-range></form> `);
|
||||
const range = el.querySelector<SlRange>('sl-range')!;
|
||||
|
||||
range.setCustomValidity('Invalid value');
|
||||
await range.updateComplete;
|
||||
|
||||
expect(range.hasAttribute('data-invalid')).to.be.true;
|
||||
expect(range.hasAttribute('data-valid')).to.be.false;
|
||||
expect(range.hasAttribute('data-user-invalid')).to.be.false;
|
||||
expect(range.hasAttribute('data-user-valid')).to.be.false;
|
||||
});
|
||||
|
||||
it('should be present in form data when using the form attribute and located outside of a <form>', async () => {
|
||||
const el = await fixture<HTMLFormElement>(html`
|
||||
<div>
|
||||
|
||||
@@ -294,6 +294,26 @@ describe('<sl-select>', () => {
|
||||
expect(el.hasAttribute('data-user-invalid')).to.be.true;
|
||||
expect(el.hasAttribute('data-user-valid')).to.be.false;
|
||||
});
|
||||
|
||||
it('should receive validation attributes ("states") even when novalidate is used on the parent form', async () => {
|
||||
const el = await fixture<HTMLFormElement>(html`
|
||||
<form novalidate>
|
||||
<sl-select required>
|
||||
<sl-option value="option-1">Option 1</sl-option>
|
||||
<sl-option value="option-2">Option 2</sl-option>
|
||||
<sl-option value="option-3">Option 3</sl-option>
|
||||
</sl-select>
|
||||
</form>
|
||||
`);
|
||||
const select = el.querySelector<SlSelect>('sl-select')!;
|
||||
|
||||
expect(select.hasAttribute('data-required')).to.be.true;
|
||||
expect(select.hasAttribute('data-optional')).to.be.false;
|
||||
expect(select.hasAttribute('data-invalid')).to.be.true;
|
||||
expect(select.hasAttribute('data-valid')).to.be.false;
|
||||
expect(select.hasAttribute('data-user-invalid')).to.be.false;
|
||||
expect(select.hasAttribute('data-user-valid')).to.be.false;
|
||||
});
|
||||
});
|
||||
|
||||
describe('when submitting a form', () => {
|
||||
|
||||
@@ -217,6 +217,18 @@ describe('<sl-switch>', () => {
|
||||
|
||||
expect(formData.get('a')).to.equal('1');
|
||||
});
|
||||
|
||||
it('should receive validation attributes ("states") even when novalidate is used on the parent form', async () => {
|
||||
const el = await fixture<HTMLFormElement>(html` <form novalidate><sl-switch required></sl-switch></form> `);
|
||||
const slSwitch = el.querySelector<SlSwitch>('sl-switch')!;
|
||||
|
||||
expect(slSwitch.hasAttribute('data-required')).to.be.true;
|
||||
expect(slSwitch.hasAttribute('data-optional')).to.be.false;
|
||||
expect(slSwitch.hasAttribute('data-invalid')).to.be.true;
|
||||
expect(slSwitch.hasAttribute('data-valid')).to.be.false;
|
||||
expect(slSwitch.hasAttribute('data-user-invalid')).to.be.false;
|
||||
expect(slSwitch.hasAttribute('data-user-valid')).to.be.false;
|
||||
});
|
||||
});
|
||||
|
||||
describe('when resetting a form', () => {
|
||||
|
||||
@@ -171,6 +171,18 @@ describe('<sl-textarea>', () => {
|
||||
expect(el.hasAttribute('data-user-invalid')).to.be.true;
|
||||
expect(el.hasAttribute('data-user-valid')).to.be.false;
|
||||
});
|
||||
|
||||
it('should receive validation attributes ("states") even when novalidate is used on the parent form', async () => {
|
||||
const el = await fixture<HTMLFormElement>(html` <form novalidate><sl-textarea required></sl-textarea></form> `);
|
||||
const textarea = el.querySelector<SlTextarea>('sl-textarea')!;
|
||||
|
||||
expect(textarea.hasAttribute('data-required')).to.be.true;
|
||||
expect(textarea.hasAttribute('data-optional')).to.be.false;
|
||||
expect(textarea.hasAttribute('data-invalid')).to.be.true;
|
||||
expect(textarea.hasAttribute('data-valid')).to.be.false;
|
||||
expect(textarea.hasAttribute('data-user-invalid')).to.be.false;
|
||||
expect(textarea.hasAttribute('data-user-valid')).to.be.false;
|
||||
});
|
||||
});
|
||||
|
||||
describe('when submitting a form', () => {
|
||||
|
||||
@@ -294,23 +294,12 @@ export class FormControlController implements ReactiveController {
|
||||
//
|
||||
// See this RFC for more details: https://github.com/shoelace-style/shoelace/issues/1011
|
||||
//
|
||||
if (this.form?.noValidate) {
|
||||
// Form validation is disabled, remove the attributes
|
||||
host.removeAttribute('data-required');
|
||||
host.removeAttribute('data-optional');
|
||||
host.removeAttribute('data-invalid');
|
||||
host.removeAttribute('data-valid');
|
||||
host.removeAttribute('data-user-invalid');
|
||||
host.removeAttribute('data-user-valid');
|
||||
} else {
|
||||
// Form validation is enabled, set the attributes
|
||||
host.toggleAttribute('data-required', required);
|
||||
host.toggleAttribute('data-optional', !required);
|
||||
host.toggleAttribute('data-invalid', !isValid);
|
||||
host.toggleAttribute('data-valid', isValid);
|
||||
host.toggleAttribute('data-user-invalid', !isValid && hasInteracted);
|
||||
host.toggleAttribute('data-user-valid', isValid && hasInteracted);
|
||||
}
|
||||
host.toggleAttribute('data-required', required);
|
||||
host.toggleAttribute('data-optional', !required);
|
||||
host.toggleAttribute('data-invalid', !isValid);
|
||||
host.toggleAttribute('data-valid', isValid);
|
||||
host.toggleAttribute('data-user-invalid', !isValid && hasInteracted);
|
||||
host.toggleAttribute('data-user-valid', isValid && hasInteracted);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user