| // Copyright (c) 2021 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import * as SDK from '../../../core/sdk/sdk.js'; |
| import * as ComponentHelpers from '../../../ui/components/helpers/helpers.js'; |
| import * as IconButton from '../../../ui/components/icon_button/icon_button.js'; |
| import * as LitHtml from '../../../ui/lit-html/lit-html.js'; |
| |
| import type {DOMNode} from './Helper.js'; |
| import {NodeText} from './NodeText.js'; |
| import type {NodeTextData} from './NodeText.js'; |
| import queryContainerStyles from './queryContainer.css.js'; |
| |
| const {render, html} = LitHtml; |
| const {PhysicalAxis, QueryAxis} = SDK.CSSContainerQuery; |
| |
| export class QueriedSizeRequestedEvent extends Event { |
| static readonly eventName = 'queriedsizerequested'; |
| constructor() { |
| super(QueriedSizeRequestedEvent.eventName, {}); |
| } |
| } |
| |
| export interface QueryContainerData { |
| container: DOMNode; |
| queryName?: string; |
| onContainerLinkClick: (event: Event) => void; |
| } |
| |
| export class QueryContainer extends HTMLElement { |
| static readonly litTagName = LitHtml.literal`devtools-query-container`; |
| |
| readonly #shadow = this.attachShadow({mode: 'open'}); |
| #queryName?: string; |
| #container?: DOMNode; |
| #onContainerLinkClick?: (event: Event) => void; |
| #isContainerLinkHovered = false; |
| #queriedSizeDetails?: SDK.CSSContainerQuery.ContainerQueriedSizeDetails; |
| |
| set data(data: QueryContainerData) { |
| this.#queryName = data.queryName; |
| this.#container = data.container; |
| this.#onContainerLinkClick = data.onContainerLinkClick; |
| this.#render(); |
| } |
| |
| connectedCallback(): void { |
| this.#shadow.adoptedStyleSheets = [queryContainerStyles]; |
| } |
| |
| updateContainerQueriedSizeDetails(details: SDK.CSSContainerQuery.ContainerQueriedSizeDetails): void { |
| this.#queriedSizeDetails = details; |
| this.#render(); |
| } |
| |
| async #onContainerLinkMouseEnter(): Promise<void> { |
| this.#container?.highlightNode('container-outline'); |
| this.#isContainerLinkHovered = true; |
| this.dispatchEvent(new QueriedSizeRequestedEvent()); |
| } |
| |
| #onContainerLinkMouseLeave(): void { |
| this.#container?.clearHighlight(); |
| this.#isContainerLinkHovered = false; |
| this.#render(); |
| } |
| |
| #render(): void { |
| if (!this.#container) { |
| return; |
| } |
| |
| let idToDisplay, classesToDisplay; |
| if (!this.#queryName) { |
| idToDisplay = this.#container.getAttribute('id'); |
| classesToDisplay = this.#container.getAttribute('class')?.split(/\s+/).filter(Boolean); |
| } |
| |
| const nodeTitle = this.#queryName || this.#container.nodeNameNicelyCased; |
| |
| // Disabled until https://crbug.com/1079231 is fixed. |
| // clang-format off |
| // eslint-disable-next-line rulesdir/ban_a_tags_in_lit_html |
| render(html` |
| → |
| <a href="#" |
| draggable=false |
| class="container-link" |
| @click=${this.#onContainerLinkClick} |
| @mouseenter=${this.#onContainerLinkMouseEnter} |
| @mouseleave=${this.#onContainerLinkMouseLeave} |
| ><${NodeText.litTagName} |
| data-node-title=${nodeTitle} |
| .data=${{ |
| nodeTitle, |
| nodeId: idToDisplay, |
| nodeClasses: classesToDisplay, |
| } as NodeTextData}></${NodeText.litTagName}></a> |
| ${this.#isContainerLinkHovered ? this.#renderQueriedSizeDetails() : LitHtml.nothing} |
| `, this.#shadow, { |
| host: this, |
| }); |
| // clang-format on |
| } |
| |
| #renderQueriedSizeDetails(): LitHtml.LitTemplate { |
| if (!this.#queriedSizeDetails || this.#queriedSizeDetails.queryAxis === QueryAxis.None) { |
| return LitHtml.nothing; |
| } |
| |
| const areBothAxesQueried = this.#queriedSizeDetails.queryAxis === QueryAxis.Both; |
| |
| const axisIconClasses = LitHtml.Directives.classMap({ |
| 'axis-icon': true, |
| 'hidden': areBothAxesQueried, |
| 'vertical': this.#queriedSizeDetails.physicalAxis === PhysicalAxis.Vertical, |
| }); |
| |
| // Disabled until https://crbug.com/1079231 is fixed. |
| // clang-format off |
| return html` |
| <span class="queried-size-details"> |
| (${this.#queriedSizeDetails.queryAxis}<${IconButton.Icon.Icon.litTagName} |
| class=${axisIconClasses} .data=${{ |
| iconName: 'ic_dimension_single', |
| color: 'var(--color-text-primary)', |
| } as IconButton.Icon.IconData}></${IconButton.Icon.Icon.litTagName}>) |
| ${areBothAxesQueried && this.#queriedSizeDetails.width ? 'width:' : LitHtml.nothing} |
| ${this.#queriedSizeDetails.width || LitHtml.nothing} |
| ${areBothAxesQueried && this.#queriedSizeDetails.height ? 'height:' : LitHtml.nothing} |
| ${this.#queriedSizeDetails.height || LitHtml.nothing} |
| </span> |
| `; |
| // clang-format on |
| } |
| } |
| |
| ComponentHelpers.CustomElements.defineComponent('devtools-query-container', QueryContainer); |
| |
| declare global { |
| // eslint-disable-next-line @typescript-eslint/no-unused-vars |
| interface HTMLElementTagNameMap { |
| 'devtools-query-container': QueryContainer; |
| } |
| } |