| // Copyright 2021 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| /* eslint-disable @devtools/no-lit-render-outside-of-view, @devtools/enforce-custom-element-definitions-location */ |
| |
| import '../../kit/kit.js'; |
| |
| import * as Lit from '../../lit/lit.js'; |
| |
| import iconButtonStyles from './iconButton.css.js'; |
| |
| const {html} = Lit; |
| |
| export interface IconWithTextData { |
| iconName: string; |
| iconColor?: string; |
| iconWidth?: string; |
| iconHeight?: string; |
| text?: string; |
| } |
| |
| export interface IconButtonData { |
| clickHandler?: () => void; |
| groups: IconWithTextData[]; |
| leadingText?: string; |
| trailingText?: string; |
| accessibleName?: string; |
| compact?: boolean; |
| } |
| |
| export class IconButton extends HTMLElement { |
| readonly #shadow = this.attachShadow({mode: 'open'}); |
| #clickHandler?: () => void; |
| #groups: IconWithTextData[] = []; |
| #compact = false; |
| #leadingText = ''; |
| #trailingText = ''; |
| #accessibleName?: string; |
| |
| set data(data: IconButtonData) { |
| this.#groups = data.groups.map(group => ({...group})); // Ensure we make a deep copy. |
| this.#clickHandler = data.clickHandler; |
| this.#trailingText = data.trailingText ?? ''; |
| this.#leadingText = data.leadingText ?? ''; |
| this.#accessibleName = data.accessibleName; |
| this.#compact = Boolean(data.compact); |
| this.#render(); |
| } |
| |
| get data(): IconButtonData { |
| return { |
| groups: this.#groups.map(group => ({...group})), // Ensure we make a deep copy. |
| accessibleName: this.#accessibleName, |
| clickHandler: this.#clickHandler, |
| leadingText: this.#leadingText, |
| trailingText: this.#trailingText, |
| compact: this.#compact, |
| }; |
| } |
| |
| #onClickHandler(event: Event): void { |
| if (this.#clickHandler) { |
| event.preventDefault(); |
| this.#clickHandler(); |
| } |
| } |
| |
| #render(): void { |
| const buttonClasses = Lit.Directives.classMap({ |
| 'icon-button': true, |
| 'with-click-handler': Boolean(this.#clickHandler), |
| compact: this.#compact, |
| }); |
| const filteredGroups = this.#groups.filter(counter => counter.text !== undefined) |
| .filter((_, index) => this.#compact ? index === 0 : true); |
| // Disabled until https://crbug.com/1079231 is fixed. |
| // clang-format off |
| Lit.render(html` |
| <style>${iconButtonStyles}</style> |
| <button class=${buttonClasses} @click=${this.#onClickHandler} aria-label=${Lit.Directives.ifDefined(this.#accessibleName)}> |
| ${(!this.#compact && this.#leadingText) ? html`<span class="icon-button-title">${this.#leadingText}</span>` : Lit.nothing} |
| ${filteredGroups.map(counter => |
| html` |
| <devtools-icon class="status-icon" name=${counter.iconName} style="color: ${counter.iconColor}; width: ${counter.iconWidth || 'var(--sys-size-7)'}; height: ${counter.iconHeight || 'var(--sys-size-7)'}"> |
| </devtools-icon> |
| ${this.#compact ? html`<!-- Force line-height for this element --><span>​</span>` : Lit.nothing} |
| <span class="icon-button-title">${counter.text}</span>`, |
| )} |
| </button> |
| ${(!this.#compact && this.#trailingText) ? html`<span class="icon-button-title">${this.#trailingText}</span>` : Lit.nothing} |
| `, this.#shadow, { host: this}); |
| // clang-format on |
| } |
| } |
| |
| // eslint-disable-next-line @devtools/enforce-custom-element-prefix |
| customElements.define('icon-button', IconButton); |
| |
| declare global { |
| interface HTMLElementTagNameMap { |
| 'icon-button': IconButton; |
| } |
| } |