diff --git a/button/internal/button.ts b/button/internal/button.ts index a07e922d85..70469e3411 100644 --- a/button/internal/button.ts +++ b/button/internal/button.ts @@ -14,14 +14,17 @@ import {html as staticHtml, literal} from 'lit/static-html.js'; import {ARIAMixinStrict} from '../../internal/aria/aria.js'; import {requestUpdateOnAriaChange} from '../../internal/aria/delegate.js'; -import {dispatchActivationClick, isActivationClick, redispatchEvent} from '../../internal/controller/events.js'; +import {internals} from '../../internal/controller/element-internals.js'; +import {dispatchActivationClick, isActivationClick} from '../../internal/controller/events.js'; +import {FormSubmitter, FormSubmitterType, setupFormSubmitter} from '../../internal/controller/form-submitter.js'; /** * A button component. */ -export abstract class Button extends LitElement { +export abstract class Button extends LitElement implements FormSubmitter { static { requestUpdateOnAriaChange(Button); + setupFormSubmitter(Button); } /** @nocollapse */ @@ -62,28 +65,17 @@ export abstract class Button extends LitElement { */ @property({type: Boolean, attribute: 'has-icon'}) hasIcon = false; - /** - * A string indicating the behavior of the button. - * - * - submit: The button submits the form. This is the default value if the - * attribute is not specified, or if it is dynamically changed to an empty or - * invalid value. - * - reset: The button resets the form. - * - button: The button does nothing. - */ - @property() type: 'button'|'submit'|'reset' = 'submit'; + @property() type: FormSubmitterType = 'submit'; @query('.button') private readonly buttonElement!: HTMLElement|null; @queryAssignedElements({slot: 'icon', flatten: true}) private readonly assignedIcons!: HTMLElement[]; - private readonly internals = + /** @private */ + [internals] = (this as HTMLElement /* needed for closure */).attachInternals(); - // flag to avoid processing redispatched event. - private isRedispatchingEvent = false; - constructor() { super(); if (!isServer) { @@ -115,7 +107,6 @@ export abstract class Button extends LitElement { aria-expanded="${ariaExpanded || nothing}" href=${this.href || nothing} target=${this.target || nothing} - @click="${this.handleClick}" > ${this.renderFocusRing()} ${this.renderElevation()} @@ -183,43 +174,6 @@ export abstract class Button extends LitElement { this.handleSlotChange}">`; } - private handleClick(event: MouseEvent) { - if (this.isRedispatchingEvent) { - return; - } - // based on type, trigger form action. - const {type, internals: {form}} = this; - if (!form || type === 'button') { - return; - } - - this.isRedispatchingEvent = true; - const prevented = !redispatchEvent(this, event); - this.isRedispatchingEvent = false; - if (prevented) { - return; - } - - if (type === 'reset') { - form.reset(); - return; - } - - // form.requestSubmit(submitter) does not work with form associated custom - // elements. This patches the dispatched submit event to add the correct - // `submitter`. - // See https://github.com/WICG/webcomponents/issues/814 - form.addEventListener('submit', submitEvent => { - Object.defineProperty(submitEvent, 'submitter', { - configurable: true, - enumerable: true, - get: () => this, - }); - }, {capture: true, once: true}); - - form.requestSubmit(); - } - private handleSlotChange() { this.hasIcon = this.assignedIcons.length > 0; } diff --git a/button/internal/button_test.ts b/button/internal/button_test.ts deleted file mode 100644 index 7cac337d69..0000000000 --- a/button/internal/button_test.ts +++ /dev/null @@ -1,97 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -// import 'jasmine'; (google3-only) - -import {html} from 'lit'; - -import {Environment} from '../../testing/environment.js'; -import {ButtonHarness} from '../harness.js'; - -import {Button} from './button.js'; - -customElements.define('test-button', class extends Button {}); - -describe('Button', () => { - const env = new Environment(); - describe('form associated', () => { - async function setupTest() { - const root = env.render(html`
`); - const element = root.querySelector