UNPKG

chrome-devtools-frontend

Version:
178 lines (162 loc) 4.79 kB
// 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. /* eslint-disable rulesdir/no-imperative-dom-api */ import '../../../Images/Images.js'; import iconStyles from './icon.css.js'; /** * @deprecated */ export interface IconWithName { iconName: string; color: string; width?: string; height?: string; } /** * @deprecated */ export type IconData = IconWithName|{ iconPath: string, color: string, width?: string, height?: string, }; /** * A simple icon component to display SVG icons from the `front_end/Images/src` * folder (via the `--image-file-<name>` CSS variables). * * Usage is simple: * * ```js * // Instantiate programmatically via the `create()` helper: * const icon = IconButton.Icon.create('bin'); * const iconWithClassName = IconButton.Icon.create('bin', 'delete-icon'); * * // Use within a template: * Lit.html` * <devtools-icon name="bin"> * </devtools-icon> * `; * ``` * * The color for the icon defaults to `var(--icon-default)`, while the dimensions * default to 20px times 20px. You can change both color and size via CSS: * * ```css * devtools-icon.my-icon { * color: red; * width: 14px; * height: 14px; * } * ``` * * For `'triangle-up'`, `'triangle-down'`, `'triangle-left'`, and `'triangle-right'` * the default dimensions are 14px times 14px, and the default `vertical-align` is * `baseline` (instead of `sub`). * * @attr name - The basename of the icon file (not including the `.svg` suffix). For * backwards compatibility we also support a full URL here, but that * should not be used in newly written code. * @prop {String} name - The `"name"` attribute is reflected as property. * @prop {IconData} data - Deprecated way to set dimensions, color and name at once. */ export class Icon extends HTMLElement { static readonly observedAttributes = ['name']; readonly #shadowRoot; readonly #icon; constructor() { super(); this.role = 'presentation'; const style = document.createElement('style'); style.textContent = iconStyles; this.#icon = document.createElement('span'); this.#shadowRoot = this.attachShadow({mode: 'open'}); this.#shadowRoot.append(style, this.#icon); } /** * @deprecated use `name` and CSS instead. */ get data(): IconData { return { color: this.style.color, width: this.style.width, height: this.style.height, iconName: this.name ?? '', }; } /** * @deprecated use `name` and CSS instead. */ set data(data: IconData) { const {color, width = '20px', height = '20px'} = data; this.style.color = color; this.style.width = width; this.style.height = height; if ('iconName' in data && data.iconName) { this.name = data.iconName; } else if ('iconPath' in data && data.iconPath) { this.name = data.iconPath; } else { throw new Error('Misconfigured `iconName` or `iconPath`.'); } } /** * Yields the value of the `"name"` attribute of this `Icon` (`null` in case * there's no `"name"` on this element). */ get name(): string|null { return this.getAttribute('name'); } /** * Changes the value of the `"name"` attribute of this `Icon`. If you pass * `null` the `"name"` attribute will be removed from this element. * * @param name the new icon name or `null` to unset. */ set name(name: string|null) { if (name === null) { this.removeAttribute('name'); } else { this.setAttribute('name', name); } } attributeChangedCallback(name: string, oldValue: string|null, newValue: string|null): void { if (oldValue === newValue) { return; } switch (name) { case 'name': { if (newValue === null) { this.#icon.style.removeProperty('--icon-url'); } else { const url = URL.canParse(newValue) ? `url(${newValue})` : `var(--image-file-${newValue})`; this.#icon.style.setProperty('--icon-url', url); } break; } } } } /** * Helper function to programmatically create an `Icon` isntance with a given * `name` and an optional CSS `className`. * * @param name the name of the icon to use. * @param className optional CSS class name(s) to put onto the element. * @return the newly created `Icon` instance. */ export const create = (name: string, className?: string): Icon => { const icon = new Icon(); icon.name = name; if (className !== undefined) { icon.className = className; } return icon; }; customElements.define('devtools-icon', Icon); declare global { interface HTMLElementTagNameMap { 'devtools-icon': Icon; } }