chrome-devtools-frontend
Version:
Chrome DevTools UI
133 lines (115 loc) • 4.87 kB
text/typescript
// Copyright (c) 2024 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 '../../../ui/components/icon_button/icon_button.js';
import '../../../ui/legacy/components/inline_editor/inline_editor.js';
import * as i18n from '../../../core/i18n/i18n.js';
import type * as SDK from '../../../core/sdk/sdk.js';
import type * as InlineEditor from '../../../ui/legacy/components/inline_editor/inline_editor.js';
import * as Lit from '../../../ui/lit/lit.js';
import * as VisualLogging from '../../../ui/visual_logging/visual_logging.js';
import anchorFunctionLinkSwatchStylesRaw from './anchorFunctionLinkSwatch.css.js';
// TODO(crbug.com/391381439): Fully migrate off of constructed style sheets.
const anchorFunctionLinkSwatchStyles = new CSSStyleSheet();
anchorFunctionLinkSwatchStyles.replaceSync(anchorFunctionLinkSwatchStylesRaw.cssContent);
const UIStrings = {
/**
*@description Title in the styles tab for the icon button for jumping to the anchor node.
*/
jumpToAnchorNode: 'Jump to anchor node',
};
const str_ = i18n.i18n.registerUIStrings('panels/elements/components/AnchorFunctionLinkSwatch.ts', UIStrings);
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
const {render, html} = Lit;
// Clang format is messing up the formatting of the functions below. It's best
// to leave formatting off for this type declaration.
// clang-format off
export interface AnchorFunctionLinkSwatchData {
onLinkActivate: () => void;
onMouseEnter: () => void;
onMouseLeave: () => void;
// The dashed identifier for the anchor function.
// It is undefined when we're rendering for implicit or default anchor cases.
identifier?: string;
// The anchor node, it is undefined when it is not resolved correctly.
anchorNode?: SDK.DOMModel.DOMNode;
// Whether to add a space after the link or not. This is needed because for some cases,
// even though the link swatch is created; there might not be any links rendered for it.
// So adding the space from the outside causes an unnecessary space to be rendered for these cases.
// That's the reason we're controlling space behavior from the inside.
// However for `position-anchor: --dashed-ident` case, there is no space needed at all.
// That's why we need the parameter so that we don't render a space for that case.
needsSpace?: boolean;
}
// clang-format on
export class AnchorFunctionLinkSwatch extends HTMLElement {
readonly #shadow = this.attachShadow({mode: 'open'});
#data: AnchorFunctionLinkSwatchData;
constructor(data: AnchorFunctionLinkSwatchData) {
super();
this.#data = data;
}
dataForTest(): AnchorFunctionLinkSwatchData {
return this.#data;
}
connectedCallback(): void {
this.#shadow.adoptedStyleSheets = [anchorFunctionLinkSwatchStyles];
this.render();
}
set data(data: AnchorFunctionLinkSwatchData) {
this.#data = data;
this.render();
}
#handleIconClick(ev: MouseEvent): void {
ev.stopPropagation();
this.#data.onLinkActivate();
}
#renderIdentifierLink(): Lit.LitTemplate {
// clang-format off
return html`<devtools-link-swatch
=${this.#data.onMouseEnter}
=${this.#data.onMouseLeave}
.data=${{
text: this.#data.identifier,
isDefined: Boolean(this.#data.anchorNode),
jslogContext: 'anchor-link',
onLinkActivate: this.#data.onLinkActivate,
} as InlineEditor.LinkSwatch.LinkSwatchRenderData}></devtools-link-swatch>`;
// clang-format on
}
#renderIconLink(): Lit.LitTemplate {
// clang-format off
return html`<devtools-icon
role='button'
title=${i18nString(UIStrings.jumpToAnchorNode)}
class='icon-link'
name='open-externally'
jslog=${VisualLogging.action('jump-to-anchor-node').track({click: true})}
=${this.#data.onMouseEnter}
=${this.#data.onMouseLeave}
=${(ev: MouseEvent) => ev.stopPropagation()}
=${this.#handleIconClick}
></devtools-icon>`;
// clang-format on
}
protected render(): void {
if (!this.#data.identifier && !this.#data.anchorNode) {
return;
}
if (this.#data.identifier) {
// clang-format off
render(html`${this.#renderIdentifierLink()}${this.#data.needsSpace ? ' ' : ''}`, this.#shadow, {host: this});
// clang-format on
} else {
// clang-format off
render(html`${this.#renderIconLink()}${this.#data.needsSpace ? ' ' : ''}`, this.#shadow, {host: this});
// clang-format on
}
}
}
customElements.define('devtools-anchor-function-link-swatch', AnchorFunctionLinkSwatch);
declare global {
interface HTMLElementTagNameMap {
'devtools-anchor-function-link-swatch': AnchorFunctionLinkSwatch;
}
}