improve form control listeners

pull/731/head
Cory LaViska 2022-04-11 10:36:16 -04:00
rodzic 5e444a4f7c
commit fc938ea3eb
2 zmienionych plików z 15 dodań i 18 usunięć

Wyświetl plik

@ -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 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)
- 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
- Removed path aliasing (again) because it doesn't work with Web Test Runner's esbuild plugin

Wyświetl plik

@ -20,7 +20,6 @@ export interface FormSubmitControllerOptions {
export class FormSubmitController implements ReactiveController {
host?: ReactiveControllerHost & Element;
form?: HTMLFormElement | null;
options: FormSubmitControllerOptions;
constructor(host: ReactiveControllerHost & Element, options?: Partial<FormSubmitControllerOptions>) {
@ -40,20 +39,15 @@ export class FormSubmitController implements ReactiveController {
}
hostConnected() {
this.form = this.options.form(this.host);
if (this.form) {
this.form.addEventListener('formdata', this.handleFormData);
this.form.addEventListener('submit', this.handleFormSubmit);
}
// 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.
document.addEventListener('formdata', this.handleFormData, { capture: true });
document.addEventListener('submit', this.handleFormSubmit, { capture: true });
}
hostDisconnected() {
if (this.form) {
this.form.removeEventListener('formdata', this.handleFormData);
this.form.removeEventListener('submit', this.handleFormSubmit);
this.form = undefined;
}
document.removeEventListener('formdata', this.handleFormData, { capture: true });
document.removeEventListener('submit', this.handleFormSubmit, { capture: true });
}
handleFormData(event: FormDataEvent) {
@ -73,10 +67,11 @@ export class FormSubmitController implements ReactiveController {
}
handleFormSubmit(event: Event) {
const form = this.options.form(this.host);
const disabled = this.options.disabled(this.host);
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.stopImmediatePropagation();
}
@ -84,15 +79,16 @@ export class FormSubmitController implements ReactiveController {
/** Submits the form, triggering validation and form data injection. */
submit(submitter?: HTMLInputElement | SlButton) {
// 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.
if (this.form) {
const form = this.options.form(this.host);
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');
button.type = 'submit';
button.style.position = 'absolute';
button.style.width = '0';
button.style.height = '0';
button.style.clip = 'rect(0 0 0 0)';
button.style.clipPath = 'inset(50%)';
button.style.overflow = 'hidden';
button.style.whiteSpace = 'nowrap';
@ -106,7 +102,7 @@ export class FormSubmitController implements ReactiveController {
});
}
this.form.append(button);
form.append(button);
button.click();
button.remove();
}