kopia lustrzana https://github.com/shoelace-style/shoelace
improve form control listeners
rodzic
5e444a4f7c
commit
fc938ea3eb
|
@ -18,6 +18,7 @@ _During the beta period, these restrictions may be relaxed in the event of a mis
|
||||||
- Fixed a bug that resulted in a console error being thrown on keydown in `<sl-dropdown>` [#719](https://github.com/shoelace-style/shoelace/issues/719)
|
- Fixed a bug that resulted in a console error being thrown on keydown in `<sl-dropdown>` [#719](https://github.com/shoelace-style/shoelace/issues/719)
|
||||||
- Fixed a bug that prevented `<sl-dropdown>` from being closed when opened initially [#720](https://github.com/shoelace-style/shoelace/issues/720)
|
- Fixed a bug that prevented `<sl-dropdown>` from being closed when opened initially [#720](https://github.com/shoelace-style/shoelace/issues/720)
|
||||||
- Fixed a bug that caused the test runner to fail when using a locale other than en-US [#726](https://github.com/shoelace-style/shoelace/issues/726)
|
- Fixed a bug that caused the test runner to fail when using a locale other than en-US [#726](https://github.com/shoelace-style/shoelace/issues/726)
|
||||||
|
- Improved form submit logic so most user-added event listeners will run after form data is attached and validation occurs [#718](https://github.com/shoelace-style/shoelace/issues/718)
|
||||||
- Updated `<sl-tab-group>` and `<sl-menu>` to cycle through tabs and menu items instead of stopping at the first/last when using the keyboard
|
- Updated `<sl-tab-group>` and `<sl-menu>` to cycle through tabs and menu items instead of stopping at the first/last when using the keyboard
|
||||||
- Removed path aliasing (again) because it doesn't work with Web Test Runner's esbuild plugin
|
- Removed path aliasing (again) because it doesn't work with Web Test Runner's esbuild plugin
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,6 @@ export interface FormSubmitControllerOptions {
|
||||||
|
|
||||||
export class FormSubmitController implements ReactiveController {
|
export class FormSubmitController implements ReactiveController {
|
||||||
host?: ReactiveControllerHost & Element;
|
host?: ReactiveControllerHost & Element;
|
||||||
form?: HTMLFormElement | null;
|
|
||||||
options: FormSubmitControllerOptions;
|
options: FormSubmitControllerOptions;
|
||||||
|
|
||||||
constructor(host: ReactiveControllerHost & Element, options?: Partial<FormSubmitControllerOptions>) {
|
constructor(host: ReactiveControllerHost & Element, options?: Partial<FormSubmitControllerOptions>) {
|
||||||
|
@ -40,20 +39,15 @@ export class FormSubmitController implements ReactiveController {
|
||||||
}
|
}
|
||||||
|
|
||||||
hostConnected() {
|
hostConnected() {
|
||||||
this.form = this.options.form(this.host);
|
// We use the capture phase and listen on the document to intercept the event as soon as possible. Otherwise, the
|
||||||
|
// user may attach listeners that run before we have a chance to do validation.
|
||||||
if (this.form) {
|
document.addEventListener('formdata', this.handleFormData, { capture: true });
|
||||||
this.form.addEventListener('formdata', this.handleFormData);
|
document.addEventListener('submit', this.handleFormSubmit, { capture: true });
|
||||||
this.form.addEventListener('submit', this.handleFormSubmit);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hostDisconnected() {
|
hostDisconnected() {
|
||||||
if (this.form) {
|
document.removeEventListener('formdata', this.handleFormData, { capture: true });
|
||||||
this.form.removeEventListener('formdata', this.handleFormData);
|
document.removeEventListener('submit', this.handleFormSubmit, { capture: true });
|
||||||
this.form.removeEventListener('submit', this.handleFormSubmit);
|
|
||||||
this.form = undefined;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleFormData(event: FormDataEvent) {
|
handleFormData(event: FormDataEvent) {
|
||||||
|
@ -73,10 +67,11 @@ export class FormSubmitController implements ReactiveController {
|
||||||
}
|
}
|
||||||
|
|
||||||
handleFormSubmit(event: Event) {
|
handleFormSubmit(event: Event) {
|
||||||
|
const form = this.options.form(this.host);
|
||||||
const disabled = this.options.disabled(this.host);
|
const disabled = this.options.disabled(this.host);
|
||||||
const reportValidity = this.options.reportValidity;
|
const reportValidity = this.options.reportValidity;
|
||||||
|
|
||||||
if (this.form && !this.form.noValidate && !disabled && !reportValidity(this.host)) {
|
if (event.target === form && !disabled && !form?.noValidate && !reportValidity(this.host)) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopImmediatePropagation();
|
event.stopImmediatePropagation();
|
||||||
}
|
}
|
||||||
|
@ -84,15 +79,16 @@ export class FormSubmitController implements ReactiveController {
|
||||||
|
|
||||||
/** Submits the form, triggering validation and form data injection. */
|
/** Submits the form, triggering validation and form data injection. */
|
||||||
submit(submitter?: HTMLInputElement | SlButton) {
|
submit(submitter?: HTMLInputElement | SlButton) {
|
||||||
// Calling form.submit() bypasses the submit event and constraint validation. To prevent this, we can inject a
|
const form = this.options.form(this.host);
|
||||||
// native submit button into the form, "click" it, then remove it to simulate a standard form submission.
|
|
||||||
if (this.form) {
|
if (form) {
|
||||||
|
// Calling form.submit() bypasses the submit event and constraint validation. To prevent this, we can inject a
|
||||||
|
// native submit button into the form, "click" it, then remove it to simulate a standard form submission.
|
||||||
const button = document.createElement('button');
|
const button = document.createElement('button');
|
||||||
button.type = 'submit';
|
button.type = 'submit';
|
||||||
button.style.position = 'absolute';
|
button.style.position = 'absolute';
|
||||||
button.style.width = '0';
|
button.style.width = '0';
|
||||||
button.style.height = '0';
|
button.style.height = '0';
|
||||||
button.style.clip = 'rect(0 0 0 0)';
|
|
||||||
button.style.clipPath = 'inset(50%)';
|
button.style.clipPath = 'inset(50%)';
|
||||||
button.style.overflow = 'hidden';
|
button.style.overflow = 'hidden';
|
||||||
button.style.whiteSpace = 'nowrap';
|
button.style.whiteSpace = 'nowrap';
|
||||||
|
@ -106,7 +102,7 @@ export class FormSubmitController implements ReactiveController {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.form.append(button);
|
form.append(button);
|
||||||
button.click();
|
button.click();
|
||||||
button.remove();
|
button.remove();
|
||||||
}
|
}
|
||||||
|
|
Ładowanie…
Reference in New Issue