chrome-devtools-frontend
Version:
Chrome DevTools UI
128 lines (112 loc) • 3.77 kB
text/typescript
// Copyright (c) 2020 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 ComponentHelpers from '../../../ui/components/helpers/helpers.js';
import * as LitHtml from '../../../ui/lit-html/lit-html.js';
import * as Coordinator from '../render_coordinator/render_coordinator.js';
import iconStyles from './icon.css.js';
export interface IconWithPath {
iconPath: string;
color: string;
width?: string;
height?: string;
}
export interface IconWithName {
iconName: string;
color: string;
width?: string;
height?: string;
}
export type IconData = IconWithPath|IconWithName;
const isString = (value: string|undefined): value is string => value !== undefined;
const coordinator = Coordinator.RenderCoordinator.RenderCoordinator.instance();
export class Icon extends HTMLElement {
static readonly litTagName = LitHtml.literal`devtools-icon`;
readonly #shadow = this.attachShadow({mode: 'open'});
#iconPath: Readonly<string> = '';
#color: Readonly<string> = 'rgb(110 110 110)';
#width: Readonly<string> = '100%';
#height: Readonly<string> = '100%';
#iconName?: Readonly<string>;
connectedCallback(): void {
this.#shadow.adoptedStyleSheets = [iconStyles];
}
set data(data: IconData) {
const {width, height} = data;
this.#color = data.color;
this.#width = isString(width) ? width : (isString(height) ? height : this.#width);
this.#height = isString(height) ? height : (isString(width) ? width : this.#height);
if ('iconPath' in data && data.iconPath) {
this.#iconPath = data.iconPath;
} else if ('iconName' in data && data.iconName) {
this.#iconPath = new URL(`../../../Images/${data.iconName}.svg`, import.meta.url).toString();
this.#iconName = data.iconName;
} else {
throw new Error('Misconfigured iconName or iconPath.');
}
this.#render();
}
get data(): IconData {
const commonData = {
color: this.#color,
width: this.#width,
height: this.#height,
};
if (this.#iconName) {
return {
...commonData,
iconName: this.#iconName,
};
}
return {
...commonData,
iconPath: this.#iconPath,
};
}
#getStyles(): {[key: string]: string} {
const iconPath = this.#iconPath;
const width = this.#width;
const height = this.#height;
const color = this.#color;
const commonStyles = {
width,
height,
display: 'block',
};
if (color) {
return {
...commonStyles,
webkitMaskImage: `url(${iconPath})`,
webkitMaskPosition: 'center',
webkitMaskRepeat: 'no-repeat',
// We are setting this to 99% to work around an issue where non-standard zoom levels would cause the icon to clip.
webkitMaskSize: '99%',
backgroundColor: `var(--icon-color, ${color})`,
};
}
return {
...commonStyles,
backgroundImage: `url(${iconPath})`,
backgroundPosition: 'center',
backgroundRepeat: 'no-repeat',
// We are setting this to 99% to work around an issue where non-standard zoom levels would cause the icon to clip.
backgroundSize: '99%',
};
}
#render(): void {
void coordinator.write(() => {
// clang-format off
LitHtml.render(LitHtml.html`
<div class="icon-basic" style=${LitHtml.Directives.styleMap(this.#getStyles())}></div>
`, this.#shadow, {host: this});
// clang-format on
});
}
}
ComponentHelpers.CustomElements.defineComponent('devtools-icon', Icon);
declare global {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
interface HTMLElementTagNameMap {
'devtools-icon': Icon;
}
}