From 91370623073d10709649abc9e5ba16d76e57ec42 Mon Sep 17 00:00:00 2001 From: Elizabeth Mitchell Date: Wed, 25 Oct 2023 15:06:39 -0700 Subject: [PATCH] chore(behaviors): add ElementInternals mixin PiperOrigin-RevId: 576657058 --- button/internal/button.ts | 14 ++--- iconbutton/internal/icon-button.ts | 14 ++--- internal/controller/element-internals.ts | 37 ------------- internal/controller/form-submitter.ts | 7 ++- internal/controller/form-submitter_test.ts | 7 +-- labs/behaviors/element-internals.ts | 62 ++++++++++++++++++++++ labs/behaviors/element-internals_test.ts | 37 +++++++++++++ 7 files changed, 122 insertions(+), 56 deletions(-) delete mode 100644 internal/controller/element-internals.ts create mode 100644 labs/behaviors/element-internals.ts create mode 100644 labs/behaviors/element-internals_test.ts diff --git a/button/internal/button.ts b/button/internal/button.ts index 501268dc307..a4c089d53f3 100644 --- a/button/internal/button.ts +++ b/button/internal/button.ts @@ -14,7 +14,6 @@ import {literal, html as staticHtml} from 'lit/static-html.js'; import {ARIAMixinStrict} from '../../internal/aria/aria.js'; import {requestUpdateOnAriaChange} from '../../internal/aria/delegate.js'; -import {internals} from '../../internal/controller/element-internals.js'; import { dispatchActivationClick, isActivationClick, @@ -24,11 +23,18 @@ import { FormSubmitterType, setupFormSubmitter, } from '../../internal/controller/form-submitter.js'; +import { + internals, + mixinElementInternals, +} from '../../labs/behaviors/element-internals.js'; + +// Separate variable needed for closure. +const buttonBaseClass = mixinElementInternals(LitElement); /** * A button component. */ -export abstract class Button extends LitElement implements FormSubmitter { +export abstract class Button extends buttonBaseClass implements FormSubmitter { static { requestUpdateOnAriaChange(Button); setupFormSubmitter(Button); @@ -95,10 +101,6 @@ export abstract class Button extends LitElement implements FormSubmitter { @queryAssignedElements({slot: 'icon', flatten: true}) private readonly assignedIcons!: HTMLElement[]; - /** @private */ - [internals] = (this as HTMLElement) /* needed for closure */ - .attachInternals(); - constructor() { super(); if (!isServer) { diff --git a/iconbutton/internal/icon-button.ts b/iconbutton/internal/icon-button.ts index 9162480c704..02391d75a66 100644 --- a/iconbutton/internal/icon-button.ts +++ b/iconbutton/internal/icon-button.ts @@ -14,18 +14,24 @@ import {literal, html as staticHtml} from 'lit/static-html.js'; import {ARIAMixinStrict} from '../../internal/aria/aria.js'; import {requestUpdateOnAriaChange} from '../../internal/aria/delegate.js'; -import {internals} from '../../internal/controller/element-internals.js'; import { FormSubmitter, FormSubmitterType, setupFormSubmitter, } from '../../internal/controller/form-submitter.js'; import {isRtl} from '../../internal/controller/is-rtl.js'; +import { + internals, + mixinElementInternals, +} from '../../labs/behaviors/element-internals.js'; type LinkTarget = '_blank' | '_parent' | '_self' | '_top'; +// Separate variable needed for closure. +const iconButtonBaseClass = mixinElementInternals(LitElement); + // tslint:disable-next-line:enforce-comments-on-exported-symbols -export class IconButton extends LitElement implements FormSubmitter { +export class IconButton extends iconButtonBaseClass implements FormSubmitter { static { requestUpdateOnAriaChange(IconButton); setupFormSubmitter(IconButton); @@ -106,10 +112,6 @@ export class IconButton extends LitElement implements FormSubmitter { @state() private flipIcon = isRtl(this, this.flipIconInRtl); - /** @private */ - [internals] = (this as HTMLElement) /* needed for closure */ - .attachInternals(); - /** * Link buttons cannot be disabled. */ diff --git a/internal/controller/element-internals.ts b/internal/controller/element-internals.ts deleted file mode 100644 index 3cdc3ca59c9..00000000000 --- a/internal/controller/element-internals.ts +++ /dev/null @@ -1,37 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * A unique symbol used for protected access to an instance's - * `ElementInternals`. - * - * @example - * ```ts - * class MyElement extends LitElement { - * static formAssociated = true; - * - * [internals] = this.attachInternals(); - * } - * - * function getForm(element: MyElement) { - * return element[internals].form; - * } - * ``` - */ -export const internals = Symbol('internals'); - -/** - * An instance with `ElementInternals`. - * - * Use this when protected access is needed for an instance's `ElementInternals` - * from other files. A unique symbol is used to access the internals. - */ -export interface WithInternals { - /** - * An instance's `ElementInternals`. - */ - [internals]: ElementInternals; -} diff --git a/internal/controller/form-submitter.ts b/internal/controller/form-submitter.ts index 221c64d28f1..bb99101ca59 100644 --- a/internal/controller/form-submitter.ts +++ b/internal/controller/form-submitter.ts @@ -6,7 +6,10 @@ import {isServer, ReactiveElement} from 'lit'; -import {internals, WithInternals} from './element-internals.js'; +import { + internals, + WithElementInternals, +} from '../../labs/behaviors/element-internals.js'; /** * A string indicating the form submission behavior of the element. @@ -23,7 +26,7 @@ export type FormSubmitterType = 'button' | 'submit' | 'reset'; * An element that can submit or reset a `
`, similar to * `