shoelace/src/components/icon/icon.ts

130 wiersze
3.2 KiB
TypeScript
Czysty Zwykły widok Historia

import { LitElement, html, unsafeCSS } from 'lit';
import { customElement, property, state } from 'lit/decorators';
2021-03-06 17:01:39 +00:00
import { unsafeSVG } from 'lit-html/directives/unsafe-svg';
2021-03-18 13:04:23 +00:00
import { event, EventEmitter, watch } from '../../internal/decorators';
2021-02-26 14:09:13 +00:00
import styles from 'sass:./icon.scss';
import { getIconLibrary, watchIcon, unwatchIcon } from './library';
2020-07-15 21:30:37 +00:00
import { requestIcon } from './request';
const parser = new DOMParser();
/**
2020-07-17 10:09:10 +00:00
* @since 2.0
2020-07-15 21:30:37 +00:00
* @status stable
*
* @part base - The component's base wrapper.
*/
2021-03-18 13:04:23 +00:00
@customElement('sl-icon')
2021-03-09 00:14:32 +00:00
export default class SlIcon extends LitElement {
2021-03-06 17:01:39 +00:00
static styles = unsafeCSS(styles);
2020-07-15 21:30:37 +00:00
@state() private svg = '';
2020-07-15 21:30:37 +00:00
/** The name of the icon to draw. */
2021-04-02 11:47:25 +00:00
@property() name: string;
2020-07-15 21:30:37 +00:00
/** An external URL of an SVG file. */
2021-04-02 11:47:25 +00:00
@property() src: string;
2020-07-15 21:30:37 +00:00
/** An alternative description to use for accessibility. If omitted, the name or src will be used to generate it. */
2021-04-02 11:47:25 +00:00
@property() label: string;
2020-07-15 21:30:37 +00:00
2020-10-07 13:34:05 +00:00
/** The name of a registered custom icon library. */
2021-03-06 17:01:39 +00:00
@property() library = 'default';
/** Emitted when the icon has loaded. */
@event('sl-load') slLoad: EventEmitter<void>;
2020-07-15 21:30:37 +00:00
2021-03-06 21:37:39 +00:00
/** Emitted when the icon failed to load. */
2021-03-06 17:01:39 +00:00
@event('sl-error') slError: EventEmitter<{ status: number }>;
connectedCallback() {
super.connectedCallback();
2021-02-26 14:09:13 +00:00
watchIcon(this);
}
2021-03-06 17:01:39 +00:00
firstUpdated() {
2020-07-15 21:30:37 +00:00
this.setIcon();
}
2021-03-06 17:01:39 +00:00
disconnectedCallback() {
super.disconnectedCallback();
2021-02-26 14:09:13 +00:00
unwatchIcon(this);
2020-07-15 21:30:37 +00:00
}
getLabel() {
let label = '';
if (this.label) {
label = this.label;
} else if (this.name) {
label = this.name.replace(/-/g, ' ');
} else if (this.src) {
label = this.src.replace(/.*\//, '').replace(/-/g, ' ').replace(/\.svg/i, '');
}
return label;
}
2021-02-26 14:09:13 +00:00
/** @internal Fetches the icon and redraws it. Used to handle library registrations. */
redraw() {
this.setIcon();
}
2021-03-06 19:39:48 +00:00
@watch('name')
@watch('src')
@watch('library')
async setIcon() {
2021-02-26 14:09:13 +00:00
const library = getIconLibrary(this.library);
let url = this.src;
if (this.name && library) {
url = library.resolver(this.name);
}
if (url) {
try {
2021-02-26 14:09:13 +00:00
const file = await requestIcon(url)!;
if (file.ok) {
const doc = parser.parseFromString(file.svg, 'text/html');
2021-02-26 14:09:13 +00:00
const svgEl = doc.body.querySelector('svg');
2021-02-26 14:09:13 +00:00
if (svgEl) {
2020-10-07 13:34:05 +00:00
if (library && library.mutator) {
2021-02-26 14:09:13 +00:00
library.mutator(svgEl);
2020-10-07 13:34:05 +00:00
}
2021-03-06 17:01:39 +00:00
this.svg = svgEl.outerHTML;
this.slLoad.emit();
} else {
this.svg = '';
2021-03-06 17:01:39 +00:00
this.slError.emit({ detail: { status: file.status } });
}
} else {
2021-02-26 14:09:13 +00:00
this.svg = '';
2021-03-06 17:01:39 +00:00
this.slError.emit({ detail: { status: file.status } });
}
} catch {
2021-03-06 17:01:39 +00:00
this.slError.emit({ detail: { status: -1 } });
}
} else if (this.svg) {
// If we can't resolve a URL and an icon was previously set, remove it
2021-02-26 14:09:13 +00:00
this.svg = '';
}
}
2021-02-26 14:09:13 +00:00
handleChange() {
this.setIcon();
}
2020-07-15 21:30:37 +00:00
render() {
2021-03-06 17:01:39 +00:00
return html` <div part="base" class="icon" role="img" aria-label=${this.getLabel()}>${unsafeSVG(this.svg)}</div>`;
2020-07-15 21:30:37 +00:00
}
}
2021-03-12 14:09:08 +00:00
declare global {
interface HTMLElementTagNameMap {
'sl-icon': SlIcon;
}
}